GCC Code Coverage Report


Directory: ./
File: sql-common/client.cc
Date: 2022-12-13 11:44:05
Exec Total Coverage
Lines: 3276 4136 79.2%
Branches: 2649 5854 45.3%

Line Branch Exec Source
1 /* Copyright (c) 2003, 2022, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 Without limiting anything contained in the foregoing, this file,
15 which is part of C Driver for MySQL (Connector/C), is also subject to the
16 Universal FOSS Exception, version 1.0, a copy of which can be found at
17 http://oss.oracle.com/licenses/universal-foss-exception.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License, version 2.0, for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
27
28 /*
29 This file is included by both libmysql.c (the MySQL client C API)
30 and the mysqld server to connect to another MYSQL server.
31
32 The differences for the two cases are:
33
34 - Things that only works for the client:
35 - Trying to automatically determine user name if not supplied to
36 mysql_real_connect()
37 - Support for reading local file with LOAD DATA LOCAL
38 - SHARED memory handling
39 - Prepared statements
40 - Things that only works for the server
41
42 In all other cases, code should be identical for the client and
43 server.
44 */
45
46 #include <stdarg.h>
47 #include <sys/types.h>
48
49 #include "m_ctype.h"
50 #include "m_string.h"
51 #include "my_config.h"
52 #include "my_sys.h"
53 #include "mysys_err.h"
54 #ifndef _WIN32
55 #include <netdb.h>
56 #endif
57 #ifdef HAVE_NETINET_IN_H
58 #include <netinet/in.h>
59 #endif
60 #include <stdio.h>
61
62 #include <algorithm>
63 #include <string>
64
65 #include "base64.h"
66 #include "client_async_authentication.h"
67 #include "compression.h" // validate_compression_attributes
68 #include "errmsg.h"
69 #include "lex_string.h"
70 #include "map_helpers.h"
71 #include "my_byteorder.h"
72 #include "my_compiler.h"
73 #include "my_dbug.h"
74 #include "my_default.h"
75 #include "my_inttypes.h"
76 #include "my_io.h"
77 #include "my_loglevel.h"
78 #include "my_macros.h"
79 #include "my_openssl_fips.h" // OPENSSL_ERROR_LENGTH, set_fips_mode
80 #include "my_psi_config.h"
81 #include "my_shm_defaults.h"
82 #include "mysql.h"
83 #include "mysql/client_authentication.h"
84 #include "mysql/plugin_auth_common.h"
85 #include "mysql/psi/mysql_memory.h"
86 #include "mysql/service_mysql_alloc.h"
87 #include "mysql_version.h"
88 #include "mysqld_error.h"
89 #include "template_utils.h"
90 #include "typelib.h"
91 #include "violite.h"
92
93 #if !defined(_WIN32)
94 #include "my_thread.h" /* because of signal()*/
95 #endif /* !defined(_WIN32) */
96
97 #include <signal.h>
98 #include <sys/stat.h>
99 #include <time.h>
100
101 #ifdef HAVE_PWD_H
102 #include <pwd.h>
103 #endif
104
105 #ifdef HAVE_SYS_SELECT_H
106 #include <sys/select.h>
107 #endif
108
109 #ifdef HAVE_SYS_UN_H
110 #include <sys/un.h>
111 #endif
112
113 #ifndef _WIN32
114 #include <errno.h>
115
116 #define INVALID_SOCKET -1
117 #endif
118
119 #include <mysql/client_plugin.h>
120 #include <openssl/x509v3.h>
121
122 #include <new>
123
124 #include "../libmysql/init_commands_array.h"
125 #include "../libmysql/mysql_trace.h" /* MYSQL_TRACE() instrumentation */
126 #include "sql_common.h"
127 #ifdef MYSQL_SERVER
128 #include "mysql_com_server.h"
129 #include "sql/client_settings.h"
130 #else
131 #include "libmysql/client_settings.h"
132 #endif
133 #include "client_extensions_macros.h"
134 #include "sql/log_event.h" /* Log_event_type */
135 #include "sql/rpl_constants.h" /* mysql_binlog_XXX() */
136
137 using std::string;
138 using std::swap;
139
140 #define STATE_DATA(M) \
141 (NULL != (M) ? &(MYSQL_EXTENSION_PTR(M)->state_change) : NULL)
142
143 #define ADD_INFO(M, element, type) \
144 { \
145 M = STATE_DATA(mysql); \
146 M->info_list[type].head_node = \
147 list_add(M->info_list[type].head_node, element); \
148 }
149
150 #define native_password_plugin_name "mysql_native_password"
151 #define caching_sha2_password_plugin_name "caching_sha2_password"
152
153 PSI_memory_key key_memory_mysql_options;
154 PSI_memory_key key_memory_MYSQL_DATA;
155 PSI_memory_key key_memory_MYSQL;
156 PSI_memory_key key_memory_MYSQL_RES;
157 PSI_memory_key key_memory_MYSQL_ROW;
158 PSI_memory_key key_memory_MYSQL_state_change_info;
159 PSI_memory_key key_memory_MYSQL_HANDSHAKE;
160 PSI_memory_key key_memory_MYSQL_ssl_session_data;
161
162 #if defined(_WIN32)
163 PSI_memory_key key_memory_create_shared_memory;
164 #endif /* _WIN32 */
165
166 #ifdef HAVE_PSI_INTERFACE
167 /*
168 This code is common to the client and server,
169 and also used in the server when server A connects to server B,
170 for example with replication.
171 Therefore, the code is also instrumented.
172 */
173
174 static PSI_memory_info all_client_memory[] = {
175 #if defined(_WIN32)
176 {&key_memory_create_shared_memory, "create_shared_memory", 0, 0,
177 PSI_DOCUMENT_ME},
178 #endif /* _WIN32 */
179
180 {&key_memory_mysql_options, "mysql_options", 0, 0, PSI_DOCUMENT_ME},
181 {&key_memory_MYSQL_DATA, "MYSQL_DATA", 0, 0, PSI_DOCUMENT_ME},
182 {&key_memory_MYSQL, "MYSQL", 0, 0, PSI_DOCUMENT_ME},
183 {&key_memory_MYSQL_RES, "MYSQL_RES", 0, 0, PSI_DOCUMENT_ME},
184 {&key_memory_MYSQL_ROW, "MYSQL_ROW", 0, 0, PSI_DOCUMENT_ME},
185 {&key_memory_MYSQL_state_change_info, "MYSQL_STATE_CHANGE_INFO", 0, 0,
186 PSI_DOCUMENT_ME},
187 {&key_memory_MYSQL_HANDSHAKE, "MYSQL_HANDSHAKE", 0, 0, PSI_DOCUMENT_ME},
188 {&key_memory_MYSQL_ssl_session_data, "MYSQL_SSL_session", 0, 0,
189 "Saved SSL sessions"}};
190
191 /* SSL_SESSION_is_resumable is openssl 1.1.1+ */
192 #if OPENSSL_VERSION_NUMBER < 0x10101000L
193 #define SSL_SESSION_is_resumable(x) true
194 #endif
195
196 9813 void init_client_psi_keys(void) {
197 9813 const char *category = "client";
198 int count;
199
200 9813 count = static_cast<int>(array_elements(all_client_memory));
201 9813 mysql_memory_register(category, all_client_memory, count);
202 9813 }
203
204 #endif /* HAVE_PSI_INTERFACE */
205
206 uint mysql_port = 0;
207 char *mysql_unix_port = nullptr;
208 const char *unknown_sqlstate = "HY000";
209 const char *not_error_sqlstate = "00000";
210 const char *cant_connect_sqlstate = "08001";
211 #if defined(_WIN32)
212 const char *def_shared_memory_base_name = default_shared_memory_base_name;
213 #endif
214 ulong g_net_buffer_length = 8192;
215 ulong g_max_allowed_packet = 1024L * 1024L * 1024L;
216
217 static void mysql_prune_stmt_list(MYSQL *mysql);
218 static int read_com_query_metadata(MYSQL *mysql, uchar *pos, ulong field_count);
219
220 CHARSET_INFO *default_client_charset_info = &my_charset_latin1;
221
222 /* Server error code and message */
223 unsigned int mysql_server_last_errno;
224 char mysql_server_last_error[MYSQL_ERRMSG_SIZE];
225 /* forward declaration */
226 static int read_one_row(MYSQL *mysql, uint fields, MYSQL_ROW row,
227 ulong *lengths);
228 static net_async_status read_one_row_nonblocking(MYSQL *mysql, uint fields,
229 MYSQL_ROW row, ulong *lengths,
230 int *res);
231 /**
232 Free async_qp_data buffer in async_context.
233
234 @param async_context pointer to asynchronous context structure
235 */
236 112 void inline free_async_qp_data(MYSQL_ASYNC *async_context) {
237
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 if (async_context->async_qp_data) {
238 112 my_free(async_context->async_qp_data);
239 112 async_context->async_qp_data = nullptr;
240 112 async_context->async_qp_data_length = 0;
241 }
242 112 }
243
244 /**
245 Set async_context to idle status, free async_qp_data buffer.
246
247 @param async_context pointer to asynchronous context structure
248 */
249 void inline set_query_idle(MYSQL_ASYNC *async_context) {
250 async_context->async_op_status = ASYNC_OP_UNSET;
251 async_context->async_query_state = QUERY_IDLE;
252 async_context->async_query_length = 0;
253 DBUG_PRINT("async", ("set state=%d", async_context->async_query_state));
254 free_async_qp_data(async_context);
255 }
256
257 /**
258 Convert the connect timeout option to a timeout value for VIO
259 functions (vio_socket_connect() and vio_io_wait()).
260
261 @param mysql Connection handle (client side).
262
263 @return The timeout value in milliseconds, or -1 if no timeout.
264 */
265
266 604146 static int get_vio_connect_timeout(MYSQL *mysql) {
267 int timeout_ms;
268 uint timeout_sec;
269
270 /*
271 A timeout of 0 means no timeout. Also, the connect_timeout
272 option value is in seconds, while VIO timeouts are measured
273 in milliseconds. Hence, check for a possible overflow. In
274 case of overflow, set to no timeout.
275 */
276 604146 timeout_sec = mysql->options.connect_timeout;
277
278
3/4
✓ Branch 0 taken 562080 times.
✓ Branch 1 taken 42066 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 562081 times.
604146 if (!timeout_sec || (timeout_sec > INT_MAX / 1000))
279 42065 timeout_ms = -1;
280 else
281 562081 timeout_ms = (int)(timeout_sec * 1000);
282
283 604146 return timeout_ms;
284 }
285
286 #ifdef _WIN32
287
288 /**
289 Convert the connect timeout option to a timeout value for WIN32
290 synchronization functions.
291
292 @remark Specific for WIN32 connection methods shared memory and
293 named pipe.
294
295 @param mysql Connection handle (client side).
296
297 @return The timeout value in milliseconds, or INFINITE if no timeout.
298 */
299
300 static DWORD get_win32_connect_timeout(MYSQL *mysql) {
301 DWORD timeout_ms;
302 uint timeout_sec;
303
304 /*
305 A timeout of 0 means no timeout. Also, the connect_timeout
306 option value is in seconds, while WIN32 timeouts are in
307 milliseconds. Hence, check for a possible overflow. In case
308 of overflow, set to no timeout.
309 */
310 timeout_sec = mysql->options.connect_timeout;
311
312 if (!timeout_sec || (timeout_sec > INT_MAX / 1000))
313 timeout_ms = INFINITE;
314 else
315 timeout_ms = (DWORD)(timeout_sec * 1000);
316
317 return timeout_ms;
318 }
319
320 #endif
321
322 /**
323 Set the internal error message to mysql handler
324
325 @param mysql connection handle (client side)
326 @param errcode CR_ error code, passed to ER macro to get
327 error text
328 @param sqlstate SQL standard sqlstate
329 */
330
331 18842 void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate) {
332 NET *net;
333
1/2
✓ Branch 0 taken 18842 times.
✗ Branch 1 not taken.
18842 DBUG_TRACE;
334
3/8
✓ Branch 0 taken 18842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18842 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18842 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
18842 DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER_CLIENT(errcode)));
335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18842 times.
18842 assert(mysql != nullptr);
336
337
1/2
✓ Branch 0 taken 18842 times.
✗ Branch 1 not taken.
18842 if (mysql) {
338 18842 net = &mysql->net;
339 18842 net->last_errno = errcode;
340 18842 my_stpcpy(net->last_error, ER_CLIENT(errcode));
341 18842 my_stpcpy(net->sqlstate, sqlstate);
342
2/8
✓ Branch 0 taken 10822 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10822 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10822 MYSQL_TRACE(ERROR, mysql, ());
343 } else {
344 mysql_server_last_errno = errcode;
345 my_stpcpy(mysql_server_last_error, ER_CLIENT(errcode));
346 }
347 18842 }
348
349 /**
350 Is this NET instance initialized?
351 @c my_net_init() and net_end()
352 */
353
354 1180 static bool my_net_is_inited(NET *net) { return net->buff != nullptr; }
355
356 /**
357 Clear possible error state of struct NET
358
359 @param net clear the state of the argument
360 */
361
362 17596684 void net_clear_error(NET *net) {
363 17596684 net->last_errno = 0;
364 17596684 net->last_error[0] = '\0';
365 17596684 my_stpcpy(net->sqlstate, not_error_sqlstate);
366 17596621 }
367
368 /**
369 Set an error message on the client.
370
371 @param mysql connection handle
372 @param errcode CR_* errcode, for client errors
373 @param sqlstate SQL standard sql state, unknown_sqlstate for the
374 majority of client errors.
375 @param format error message template, in sprintf format
376 @param ... variable number of arguments
377 */
378
379 326574 void set_mysql_extended_error(MYSQL *mysql, int errcode, const char *sqlstate,
380 const char *format, ...) {
381 NET *net;
382 va_list args;
383
1/2
✓ Branch 0 taken 326574 times.
✗ Branch 1 not taken.
326574 DBUG_TRACE;
384
3/8
✓ Branch 0 taken 326574 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326574 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 326574 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
326574 DBUG_PRINT("enter", ("error :%d '%s'", errcode, format));
385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 326574 times.
326574 assert(mysql != nullptr);
386
387 326574 net = &mysql->net;
388 326574 net->last_errno = errcode;
389 326574 va_start(args, format);
390 326574 vsnprintf(net->last_error, sizeof(net->last_error) - 1, format, args);
391 326574 va_end(args);
392 326574 my_stpcpy(net->sqlstate, sqlstate);
393
394
2/8
✓ Branch 0 taken 326031 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 326031 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
326031 MYSQL_TRACE(ERROR, mysql, ());
395 326574 }
396
397 /*
398 Create a named pipe connection
399 */
400
401 #ifdef _WIN32
402
403 static HANDLE create_named_pipe(MYSQL *mysql, DWORD connect_timeout,
404 const char **arg_host,
405 const char **arg_unix_socket) {
406 HANDLE hPipe = INVALID_HANDLE_VALUE;
407 char pipe_name[1024];
408 DWORD dwMode;
409 int i;
410 const char *host = *arg_host, *unix_socket = *arg_unix_socket;
411
412 if (!unix_socket || (unix_socket)[0] == 0x00) unix_socket = mysql_unix_port;
413 if (!host || !strcmp(host, LOCAL_HOST)) host = LOCAL_HOST_NAMEDPIPE;
414
415 pipe_name[sizeof(pipe_name) - 1] = 0; /* Safety if too long string */
416 strxnmov(pipe_name, sizeof(pipe_name) - 1, "\\\\.\\pipe\\", unix_socket,
417 NullS);
418
419 DBUG_PRINT("info", ("Server name: '%s'. Named Pipe: %s", host, unix_socket));
420
421 for (i = 0; i < 100; i++) /* Don't retry forever */
422 {
423 if ((hPipe = CreateFile(pipe_name,
424 FILE_READ_ATTRIBUTES | FILE_READ_DATA |
425 FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA,
426 0, NULL, OPEN_EXISTING,
427 FILE_FLAG_OVERLAPPED | SECURITY_SQOS_PRESENT |
428 SECURITY_IDENTIFICATION,
429 NULL)) != INVALID_HANDLE_VALUE)
430 break;
431 if (GetLastError() != ERROR_PIPE_BUSY) {
432 set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR, unknown_sqlstate,
433 ER_CLIENT(CR_NAMEDPIPEOPEN_ERROR), host,
434 unix_socket, (ulong)GetLastError());
435 return INVALID_HANDLE_VALUE;
436 }
437 /* wait for for an other instance */
438 if (!WaitNamedPipe(pipe_name, connect_timeout)) {
439 set_mysql_extended_error(mysql, CR_NAMEDPIPEWAIT_ERROR, unknown_sqlstate,
440 ER_CLIENT(CR_NAMEDPIPEWAIT_ERROR), host,
441 unix_socket, (ulong)GetLastError());
442 return INVALID_HANDLE_VALUE;
443 }
444 }
445 if (hPipe == INVALID_HANDLE_VALUE) {
446 set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR, unknown_sqlstate,
447 ER_CLIENT(CR_NAMEDPIPEOPEN_ERROR), host,
448 unix_socket, (ulong)GetLastError());
449 return INVALID_HANDLE_VALUE;
450 }
451 dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
452 if (!SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL)) {
453 CloseHandle(hPipe);
454 set_mysql_extended_error(mysql, CR_NAMEDPIPESETSTATE_ERROR,
455 unknown_sqlstate,
456 ER_CLIENT(CR_NAMEDPIPESETSTATE_ERROR), host,
457 unix_socket, (ulong)GetLastError());
458 return INVALID_HANDLE_VALUE;
459 }
460 *arg_host = host;
461 *arg_unix_socket = unix_socket; /* connect arg */
462 return (hPipe);
463 }
464 #endif
465
466 /*
467 Create new shared memory connection, return handler of connection
468
469 @param mysql Pointer of mysql structure
470 @param net Pointer of net structure
471 @param connect_timeout Timeout of connection (in milliseconds)
472
473 @return HANDLE to the shared memory area.
474 */
475
476 #if defined(_WIN32)
477 static HANDLE create_shared_memory(MYSQL *mysql, NET *net,
478 DWORD connect_timeout) {
479 ulong smem_buffer_length = shared_memory_buffer_length + 4;
480 /*
481 event_connect_request is event object for start connection actions
482 event_connect_answer is event object for confirm, that server put data
483 handle_connect_file_map is file-mapping object, use for create shared
484 memory
485 handle_connect_map is pointer on shared memory
486 handle_map is pointer on shared memory for client
487 event_server_wrote,
488 event_server_read,
489 event_client_wrote,
490 event_client_read are events for transfer data between server and client
491 handle_file_map is file-mapping object, use for create shared memory
492 */
493 HANDLE event_connect_request = NULL;
494 HANDLE event_connect_answer = NULL;
495 HANDLE handle_connect_file_map = NULL;
496 char *handle_connect_map = NULL;
497
498 char *handle_map = NULL;
499 HANDLE event_server_wrote = NULL;
500 HANDLE event_server_read = NULL;
501 HANDLE event_client_wrote = NULL;
502 HANDLE event_client_read = NULL;
503 HANDLE event_conn_closed = NULL;
504 HANDLE handle_file_map = NULL;
505 HANDLE connect_named_mutex = NULL;
506 ulong connect_number;
507 char connect_number_char[22], *p;
508 char *tmp = NULL;
509 char *suffix_pos = NULL;
510 DWORD error_allow = 0;
511 DWORD error_code = 0;
512 DWORD event_access_rights = SYNCHRONIZE | EVENT_MODIFY_STATE;
513 char *shared_memory_base_name = mysql->options.shared_memory_base_name;
514 static const char *name_prefixes[] = {"", "Global\\"};
515 const char *prefix;
516
517 /*
518 If this is NULL, somebody freed the MYSQL* options. mysql_close()
519 is a good candidate. We don't just silently (re)set it to
520 def_shared_memory_base_name as that would create really confusing/buggy
521 behavior if the user passed in a different name on the command-line or
522 in a my.cnf.
523 */
524 assert(shared_memory_base_name != NULL);
525
526 /*
527 get enough space base-name + '_' + longest suffix we might ever send
528 */
529 if (!(tmp = (char *)my_malloc(key_memory_create_shared_memory,
530 strlen(shared_memory_base_name) + 32L,
531 MYF(MY_FAE))))
532 goto err;
533
534 /*
535 The name of event and file-mapping events create agree next rule:
536 shared_memory_base_name+unique_part
537 Where:
538 shared_memory_base_name is unique value for each server
539 unique_part is uniquel value for each object (events and file-mapping)
540 */
541 for (size_t i = 0; i < array_elements(name_prefixes); i++) {
542 prefix = name_prefixes[i];
543 suffix_pos = strxmov(tmp, prefix, shared_memory_base_name, "_", NullS);
544 my_stpcpy(suffix_pos, "CONNECT_REQUEST");
545 event_connect_request = OpenEvent(event_access_rights, false, tmp);
546 if (event_connect_request) {
547 break;
548 }
549 }
550 if (!event_connect_request) {
551 error_allow = CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR;
552 goto err;
553 }
554 assert(suffix_pos != nullptr);
555 my_stpcpy(suffix_pos, "CONNECT_ANSWER");
556 if (!(event_connect_answer = OpenEvent(event_access_rights, false, tmp))) {
557 error_allow = CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR;
558 goto err;
559 }
560 my_stpcpy(suffix_pos, "CONNECT_DATA");
561 if (!(handle_connect_file_map =
562 OpenFileMapping(FILE_MAP_WRITE, false, tmp))) {
563 error_allow = CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR;
564 goto err;
565 }
566 if (!(handle_connect_map = static_cast<char *>(MapViewOfFile(
567 handle_connect_file_map, FILE_MAP_WRITE, 0, 0, sizeof(DWORD))))) {
568 error_allow = CR_SHARED_MEMORY_CONNECT_MAP_ERROR;
569 goto err;
570 }
571
572 my_stpcpy(suffix_pos, "CONNECT_NAMED_MUTEX");
573 connect_named_mutex = OpenMutex(SYNCHRONIZE, false, tmp);
574 if (connect_named_mutex == NULL) {
575 error_allow = CR_SHARED_MEMORY_CONNECT_SET_ERROR;
576 goto err;
577 }
578
579 if (WaitForSingleObject(connect_named_mutex, connect_timeout) !=
580 WAIT_OBJECT_0) {
581 error_allow = CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR;
582 goto err;
583 }
584
585 /* Send to server request of connection */
586 if (!SetEvent(event_connect_request)) {
587 error_allow = CR_SHARED_MEMORY_CONNECT_SET_ERROR;
588 goto err;
589 }
590
591 /* Wait of answer from server */
592 if (WaitForSingleObject(event_connect_answer, connect_timeout) !=
593 WAIT_OBJECT_0) {
594 error_allow = CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR;
595 goto err;
596 }
597
598 /* Get number of connection */
599 connect_number = uint4korr(handle_connect_map); /*WAX2*/
600
601 ReleaseMutex(connect_named_mutex);
602 CloseHandle(connect_named_mutex);
603 connect_named_mutex = NULL;
604
605 p = longlong10_to_str(connect_number, connect_number_char, 10);
606
607 /*
608 The name of event and file-mapping events create agree next rule:
609 shared_memory_base_name+unique_part+number_of_connection
610
611 Where:
612 shared_memory_base_name is uniquel value for each server
613 unique_part is uniquel value for each object (events and file-mapping)
614 number_of_connection is number of connection between server and client
615 */
616 suffix_pos = strxmov(tmp, prefix, shared_memory_base_name, "_",
617 connect_number_char, "_", NullS);
618 my_stpcpy(suffix_pos, "DATA");
619 if ((handle_file_map = OpenFileMapping(FILE_MAP_WRITE, false, tmp)) == NULL) {
620 error_allow = CR_SHARED_MEMORY_FILE_MAP_ERROR;
621 goto err2;
622 }
623 if ((handle_map = static_cast<char *>(MapViewOfFile(
624 handle_file_map, FILE_MAP_WRITE, 0, 0, smem_buffer_length))) ==
625 NULL) {
626 error_allow = CR_SHARED_MEMORY_MAP_ERROR;
627 goto err2;
628 }
629
630 my_stpcpy(suffix_pos, "SERVER_WROTE");
631 if ((event_server_wrote = OpenEvent(event_access_rights, false, tmp)) ==
632 NULL) {
633 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
634 goto err2;
635 }
636
637 my_stpcpy(suffix_pos, "SERVER_READ");
638 if ((event_server_read = OpenEvent(event_access_rights, false, tmp)) ==
639 NULL) {
640 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
641 goto err2;
642 }
643
644 my_stpcpy(suffix_pos, "CLIENT_WROTE");
645 if ((event_client_wrote = OpenEvent(event_access_rights, false, tmp)) ==
646 NULL) {
647 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
648 goto err2;
649 }
650
651 my_stpcpy(suffix_pos, "CLIENT_READ");
652 if ((event_client_read = OpenEvent(event_access_rights, false, tmp)) ==
653 NULL) {
654 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
655 goto err2;
656 }
657
658 my_stpcpy(suffix_pos, "CONNECTION_CLOSED");
659 if ((event_conn_closed = OpenEvent(event_access_rights, false, tmp)) ==
660 NULL) {
661 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
662 goto err2;
663 }
664 /*
665 Set event that server should send data
666 */
667 SetEvent(event_server_read);
668
669 err2:
670 if (error_allow == 0) {
671 net->vio = vio_new_win32shared_memory(
672 handle_file_map, handle_map, event_server_wrote, event_server_read,
673 event_client_wrote, event_client_read, event_conn_closed);
674 } else {
675 error_code = GetLastError();
676 if (event_server_read) CloseHandle(event_server_read);
677 if (event_server_wrote) CloseHandle(event_server_wrote);
678 if (event_client_read) CloseHandle(event_client_read);
679 if (event_client_wrote) CloseHandle(event_client_wrote);
680 if (event_conn_closed) CloseHandle(event_conn_closed);
681 if (handle_map) UnmapViewOfFile(handle_map);
682 if (handle_file_map) CloseHandle(handle_file_map);
683 }
684 err:
685 my_free(tmp);
686 if (error_allow) error_code = GetLastError();
687 if (event_connect_request) CloseHandle(event_connect_request);
688 if (event_connect_answer) CloseHandle(event_connect_answer);
689 if (handle_connect_map) UnmapViewOfFile(handle_connect_map);
690 if (handle_connect_file_map) CloseHandle(handle_connect_file_map);
691 if (error_allow) {
692 if (connect_named_mutex) {
693 ReleaseMutex(connect_named_mutex);
694 CloseHandle(connect_named_mutex);
695 }
696
697 if (error_allow == CR_SHARED_MEMORY_EVENT_ERROR)
698 set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
699 ER_CLIENT(error_allow), suffix_pos, error_code);
700 else
701 set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
702 ER_CLIENT(error_allow), error_code);
703 return (INVALID_HANDLE_VALUE);
704 }
705 return (handle_map);
706 }
707 #endif
708
709 /*
710 Free all memory acquired to store state change information.
711 */
712 25977033 static void free_state_change_info(MYSQL_EXTENSION *ext) {
713 STATE_INFO *info;
714 int i;
715
716
1/2
✓ Branch 0 taken 25977046 times.
✗ Branch 1 not taken.
25977033 if (ext)
717 25977046 info = &ext->state_change;
718 else
719 return;
720
721
2/2
✓ Branch 0 taken 155861975 times.
✓ Branch 1 taken 25977049 times.
181839024 for (i = SESSION_TRACK_SYSTEM_VARIABLES; i <= SESSION_TRACK_END; i++) {
722
2/2
✓ Branch 0 taken 415910 times.
✓ Branch 1 taken 155446137 times.
155861975 if (list_length(info->info_list[i].head_node) != 0) {
723 415910 list_free(info->info_list[i].head_node, (uint)0);
724 }
725 }
726 25977049 memset(info, 0, sizeof(STATE_INFO));
727 }
728
729 /**
730 Helper function to check if the buffer has at least bytes remaining
731
732 If the buffer is too small it raises CR_MALFORMED_PACKET_ERROR.
733
734 @param mysql the handle that has the buffer
735 @param packet the current position in the buffer
736 @param packet_length the size of the packet
737 @param bytes the bytes that we want available
738 @retval true the buffer has that many bytes
739 @retval false the buffer has less bytes remaining
740 */
741 55599626 inline bool buffer_check_remaining(MYSQL *mysql, uchar *packet,
742 ulong packet_length, size_t bytes) {
743 size_t remaining_bytes;
744 /* Check to avoid underflow */
745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55599626 times.
55599626 if (packet_length < (ulong)(packet - mysql->net.read_pos)) {
746 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
747 return false;
748 }
749 55599626 remaining_bytes = packet_length - (packet - mysql->net.read_pos);
750
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 55599583 times.
55599626 if (remaining_bytes < bytes) {
751 43 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
752 43 return false;
753 }
754 55599583 return true;
755 }
756
757 /*
758 Helper function to safely read a variable size from a buffer.
759 If the buffer is too small, it raises CR_MALFORMED_PACKET_ERROR
760 and sets is_error to true.
761 Otherwise it sets is_error to false and calls @ref inet_field_length_ll.
762
763 @sa @ref net_field_length_ll
764
765 @param mysql the handle to return an error in
766 @param [in,out] packet pointer to the buffer to read the length from
767 @param packet_length remaining bytes in packet
768 @param [out] is_error set to true if the buffer contains no room for a
769 full length, false otherwise.
770 @return the size read.
771 */
772 28449648 inline my_ulonglong net_field_length_ll_safe(MYSQL *mysql, uchar **packet,
773 ulong packet_length,
774 bool *is_error) {
775 28449648 size_t sizeof_len = net_field_length_size(*packet);
776
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28449669 times.
28449632 DBUG_EXECUTE_IF("simulate_bad_packet",
777 { *packet = *packet + packet_length + 1000000L; });
778
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28449665 times.
28449669 if (!buffer_check_remaining(mysql, *packet, packet_length, sizeof_len)) {
779 *is_error = true;
780 return 0;
781 }
782
783 28449665 *is_error = false;
784 28449665 return net_field_length_ll(packet);
785 }
786
787 /**
788 Read Ok packet along with the server state change information.
789 */
790 12958736 void read_ok_ex(MYSQL *mysql, ulong length) {
791 size_t total_len, len;
792 uchar *pos, *saved_pos;
793 my_ulonglong affected_rows, insert_id;
794 char *db;
795 char *data_str;
796
797 CHARSET_INFO *saved_cs;
798 bool is_charset;
799
800 12958736 STATE_INFO *info = nullptr;
801 12958736 LIST *element = nullptr;
802 12958736 LEX_STRING *data = nullptr;
803 bool is_error;
804
805 12958736 pos = mysql->net.read_pos + 1;
806
807
1/2
✓ Branch 0 taken 12958719 times.
✗ Branch 1 not taken.
12958736 affected_rows = net_field_length_ll_safe(mysql, &pos, length,
808 &is_error); /* affected rows */
809
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12958719 times.
12958719 if (is_error) return;
810 insert_id =
811
1/2
✓ Branch 0 taken 12958749 times.
✗ Branch 1 not taken.
12958719 net_field_length_ll_safe(mysql, &pos, length, &is_error); /* insert id */
812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12958749 times.
12958749 if (is_error) return;
813
814 /*
815 The following check ensures that we skip the assignment for the
816 above read fields (i.e. affected_rows and insert_id) wherein the
817 EOF packets are deprecated and the server sends OK packet instead
818 with a packet header of 0xFE (254) to identify it as an EOF packet.
819 We ignore this assignment as the valid contents of EOF packet include
820 packet marker, server status and warning count only. However, we would
821 assign these values to the connection handle if it was an OK packet
822 with a packet header of 0x00.
823 */
824
825
1/2
✓ Branch 0 taken 12958753 times.
✗ Branch 1 not taken.
12958749 if (!((mysql->server_capabilities & CLIENT_DEPRECATE_EOF) &&
826
2/2
✓ Branch 0 taken 3922617 times.
✓ Branch 1 taken 9036136 times.
12958753 mysql->net.read_pos[0] == 254)) {
827 3922613 mysql->affected_rows = affected_rows;
828 3922613 mysql->insert_id = insert_id;
829
830
3/8
✓ Branch 0 taken 3922627 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3922594 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3922594 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3922613 DBUG_PRINT("info", ("affected_rows: %lu insert_id: %lu",
831 (ulong)mysql->affected_rows, (ulong)mysql->insert_id));
832 }
833
834
2/4
✓ Branch 0 taken 12958726 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12958726 times.
12958730 if (!buffer_check_remaining(mysql, pos, length, 2)) return;
835 /* server status */
836 12958726 mysql->server_status = uint2korr(pos);
837 12958690 pos += 2;
838
839
1/2
✓ Branch 0 taken 12958690 times.
✗ Branch 1 not taken.
12958690 if (protocol_41(mysql)) {
840
3/4
✓ Branch 0 taken 12958702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43 times.
✓ Branch 3 taken 12958659 times.
12958690 if (!buffer_check_remaining(mysql, pos, length, 2)) return;
841 12958659 mysql->warning_count = uint2korr(pos);
842 12958678 pos += 2;
843 } else
844 mysql->warning_count = 0; /* MySQL 4.0 protocol */
845
846
3/8
✓ Branch 0 taken 12958698 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12958682 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12958682 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
12958678 DBUG_PRINT("info", ("status: %u warning_count: %u", mysql->server_status,
847 mysql->warning_count));
848
1/2
✓ Branch 0 taken 12958680 times.
✗ Branch 1 not taken.
12958680 if (mysql->server_capabilities & CLIENT_SESSION_TRACK) {
849
1/2
✓ Branch 0 taken 12958623 times.
✗ Branch 1 not taken.
12958680 free_state_change_info(static_cast<MYSQL_EXTENSION *>(mysql->extension));
850
851
2/2
✓ Branch 0 taken 712081 times.
✓ Branch 1 taken 12246542 times.
12958623 if (pos < mysql->net.read_pos + length) {
852 /* get the info field */
853 size_t length_msg_member =
854
1/2
✓ Branch 0 taken 712084 times.
✗ Branch 1 not taken.
712081 (size_t)net_field_length_ll_safe(mysql, &pos, length, &is_error);
855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 712084 times.
712084 if (is_error) return;
856
2/4
✓ Branch 0 taken 712084 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 712084 times.
712084 if (!buffer_check_remaining(mysql, pos, length, length_msg_member))
857 return;
858
2/2
✓ Branch 0 taken 272936 times.
✓ Branch 1 taken 439148 times.
712084 mysql->info = (length_msg_member ? (char *)pos : nullptr);
859 712084 pos += (length_msg_member);
860
861 /* read session state changes info */
862
2/2
✓ Branch 0 taken 416655 times.
✓ Branch 1 taken 295429 times.
712084 if (mysql->server_status & SERVER_SESSION_STATE_CHANGED) {
863 416655 saved_pos = pos;
864 total_len =
865
1/2
✓ Branch 0 taken 416655 times.
✗ Branch 1 not taken.
416655 (size_t)net_field_length_ll_safe(mysql, &pos, length, &is_error);
866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 416655 times.
416655 if (is_error) return;
867 /* ensure that mysql->info is zero-terminated */
868
2/2
✓ Branch 0 taken 258 times.
✓ Branch 1 taken 416397 times.
416655 if (mysql->info) *saved_pos = 0;
869
870
2/2
✓ Branch 0 taken 441482 times.
✓ Branch 1 taken 416659 times.
858141 while (total_len > 0) {
871 441482 saved_pos = pos;
872 my_ulonglong type =
873
1/2
✓ Branch 0 taken 441485 times.
✗ Branch 1 not taken.
441482 net_field_length_ll_safe(mysql, &pos, length, &is_error);
874
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 441485 times.
441485 if (is_error) return;
875
5/5
✓ Branch 0 taken 79104 times.
✓ Branch 1 taken 362230 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 108 times.
✓ Branch 4 taken 5 times.
441485 switch (type) {
876 79104 case SESSION_TRACK_SYSTEM_VARIABLES:
877 /* Move past the total length of the changed entity. */
878
1/2
✓ Branch 0 taken 79104 times.
✗ Branch 1 not taken.
79104 (void)net_field_length_ll_safe(mysql, &pos, length, &is_error);
879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79104 times.
79104 if (is_error) return;
880
881 /* Name of the system variable. */
882
1/2
✓ Branch 0 taken 79104 times.
✗ Branch 1 not taken.
79104 len = (size_t)net_field_length_ll_safe(mysql, &pos, length,
883 &is_error);
884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79104 times.
79104 if (is_error) return;
885
2/4
✓ Branch 0 taken 79104 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79104 times.
79104 if (!buffer_check_remaining(mysql, pos, length, len)) return;
886
887
2/4
✓ Branch 0 taken 79104 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79104 times.
79104 if (!my_multi_malloc(key_memory_MYSQL_state_change_info, MYF(0),
888 &element, sizeof(LIST), &data,
889 sizeof(LEX_STRING), &data_str, len, NullS)) {
890 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
891 return;
892 }
893
894 79104 data->str = data_str;
895 79104 memcpy(data->str, (char *)pos, len);
896 79104 data->length = len;
897 79104 pos += len;
898
899 79104 element->data = data;
900
3/8
✓ Branch 0 taken 79104 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 79104 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 79104 times.
✗ Branch 7 not taken.
79104 ADD_INFO(info, element, SESSION_TRACK_SYSTEM_VARIABLES);
901
902 /*
903 Check if the changed variable was charset. In that case we need
904 to update mysql->charset.
905 */
906
2/2
✓ Branch 0 taken 16383 times.
✓ Branch 1 taken 62721 times.
79104 if (!strncmp(data->str, "character_set_client", data->length))
907 16383 is_charset = true;
908 else
909 62721 is_charset = false;
910
911 /* Value of the system variable. */
912
1/2
✓ Branch 0 taken 79104 times.
✗ Branch 1 not taken.
79104 len = (size_t)net_field_length_ll_safe(mysql, &pos, length,
913 &is_error);
914
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79104 times.
79104 if (is_error) return;
915
2/4
✓ Branch 0 taken 79104 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79104 times.
79104 if (!buffer_check_remaining(mysql, pos, length, len)) return;
916
917
2/4
✓ Branch 0 taken 79104 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79104 times.
79104 if (!my_multi_malloc(key_memory_MYSQL_state_change_info, MYF(0),
918 &element, sizeof(LIST), &data,
919 sizeof(LEX_STRING), &data_str, len, NullS)) {
920 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
921 return;
922 }
923
924 79104 data->str = data_str;
925 79104 memcpy(data->str, (char *)pos, len);
926 79104 data->length = len;
927 79104 pos += len;
928
929 79104 element->data = data;
930
3/8
✓ Branch 0 taken 79104 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 79104 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 79104 times.
✗ Branch 7 not taken.
79104 ADD_INFO(info, element, SESSION_TRACK_SYSTEM_VARIABLES);
931
932
2/2
✓ Branch 0 taken 16383 times.
✓ Branch 1 taken 62721 times.
79104 if (is_charset == 1) {
933 char charset_name[MY_CS_NAME_SIZE * 8]; // MY_CS_BUFFER_SIZE
934 size_t charset_name_length =
935 16383 std::min(data->length, sizeof(charset_name) - 1);
936 16383 saved_cs = mysql->charset;
937
938 16383 memcpy(charset_name, data->str, charset_name_length);
939 16383 charset_name[charset_name_length] = 0;
940
941
2/4
✓ Branch 0 taken 16383 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16383 times.
16383 if (!(mysql->charset = get_charset_by_csname(
942 charset_name, MY_CS_PRIMARY, MYF(MY_WME)))) {
943 DBUG_PRINT(
944 "warning",
945 ("session tracker supplied %s is not a valid charset."
946 " Keeping the old one.",
947 charset_name));
948 mysql->charset = saved_cs;
949 }
950 }
951 79104 break;
952 362230 case SESSION_TRACK_TRANSACTION_STATE:
953 case SESSION_TRACK_TRANSACTION_CHARACTERISTICS:
954 case SESSION_TRACK_SCHEMA:
955
956 /* Move past the total length of the changed entity. */
957
1/2
✓ Branch 0 taken 362235 times.
✗ Branch 1 not taken.
362230 (void)net_field_length_ll_safe(mysql, &pos, length, &is_error);
958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 362235 times.
362235 if (is_error) return;
959
1/2
✓ Branch 0 taken 362234 times.
✗ Branch 1 not taken.
362235 len = (size_t)net_field_length_ll_safe(mysql, &pos, length,
960 &is_error);
961
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 362234 times.
362234 if (is_error) return;
962
2/4
✓ Branch 0 taken 362235 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 362235 times.
362234 if (!buffer_check_remaining(mysql, pos, length, len)) return;
963
964
2/4
✓ Branch 0 taken 362237 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 362237 times.
362235 if (!my_multi_malloc(key_memory_MYSQL_state_change_info, MYF(0),
965 &element, sizeof(LIST), &data,
966 sizeof(LEX_STRING), &data_str, len, NullS)) {
967 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
968 return;
969 }
970
971 362237 data->str = data_str;
972 362237 memcpy(data->str, (char *)pos, len);
973 362237 data->length = len;
974 362237 pos += len;
975
976 362237 element->data = data;
977
3/8
✓ Branch 0 taken 362237 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 362237 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 362237 times.
✗ Branch 7 not taken.
362237 ADD_INFO(info, element, type);
978
979
2/2
✓ Branch 0 taken 219039 times.
✓ Branch 1 taken 143198 times.
362237 if (type == SESSION_TRACK_SCHEMA) {
980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219039 times.
219039 if (!(db = (char *)my_malloc(key_memory_MYSQL_state_change_info,
981
1/2
✓ Branch 0 taken 219039 times.
✗ Branch 1 not taken.
219039 data->length + 1, MYF(MY_WME)))) {
982 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
983 return;
984 }
985
986
3/4
✓ Branch 0 taken 177521 times.
✓ Branch 1 taken 41518 times.
✓ Branch 2 taken 177520 times.
✗ Branch 3 not taken.
219039 if (mysql->db) my_free(mysql->db);
987
988 219038 memcpy(db, data->str, data->length);
989 219038 db[data->length] = '\0';
990 219038 mysql->db = db;
991 }
992
993 362236 break;
994 38 case SESSION_TRACK_GTIDS:
995 /* Move past the total length of the changed entity. */
996
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 (void)net_field_length_ll_safe(mysql, &pos, length, &is_error);
997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (is_error) return;
998
999 /* read (and ignore for now) the GTIDS encoding specification code
1000 */
1001
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 (void)net_field_length_ll_safe(mysql, &pos, length, &is_error);
1002
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (is_error) return;
1003
1004 /*
1005 For now we ignore the encoding specification, since only one
1006 is supported. In the future the decoding of what comes next
1007 depends on the specification code.
1008 */
1009
1010 /* read the length of the encoded string. */
1011
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 len = (size_t)net_field_length_ll_safe(mysql, &pos, length,
1012 &is_error);
1013
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (is_error) return;
1014
2/4
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
38 if (!buffer_check_remaining(mysql, pos, length, len)) return;
1015
1016
2/4
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
38 if (!my_multi_malloc(key_memory_MYSQL_state_change_info, MYF(0),
1017 &element, sizeof(LIST), &data,
1018 sizeof(LEX_STRING), &data_str, len, NullS)) {
1019 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1020 return;
1021 }
1022
1023 38 data->str = data_str;
1024 38 memcpy(data->str, (char *)pos, len);
1025 38 data->length = len;
1026 38 pos += len;
1027
1028 38 element->data = data;
1029
3/8
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 38 times.
✗ Branch 7 not taken.
38 ADD_INFO(info, element, SESSION_TRACK_GTIDS);
1030 38 break;
1031 108 case SESSION_TRACK_STATE_CHANGE:
1032 /* Get the length of the boolean tracker */
1033
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 len = (size_t)net_field_length_ll_safe(mysql, &pos, length,
1034 &is_error);
1035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (is_error) return;
1036
1037 /* length for boolean tracker is always 1 */
1038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 assert(len == 1);
1039
2/4
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 108 times.
108 if (!buffer_check_remaining(mysql, pos, length, len)) return;
1040
1041
2/4
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 108 times.
108 if (!my_multi_malloc(key_memory_MYSQL_state_change_info, MYF(0),
1042 &element, sizeof(LIST), &data,
1043 sizeof(LEX_STRING), &data_str, len, NullS)) {
1044 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1045 return;
1046 }
1047
1048 108 data->str = data_str;
1049 108 memcpy(data->str, (char *)pos, len);
1050 108 data->length = len;
1051 108 pos += len;
1052
1053 108 element->data = data;
1054
3/8
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 108 times.
✗ Branch 7 not taken.
108 ADD_INFO(info, element, SESSION_TRACK_STATE_CHANGE);
1055
1056 108 break;
1057 5 default:
1058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (type > SESSION_TRACK_END) {
1059 DBUG_PRINT(
1060 "warning",
1061 ("invalid/unknown session tracker type received: %llu",
1062 (unsigned long long)type));
1063 }
1064 /*
1065 Unknown/unsupported type received, get the total length and
1066 move past it.
1067 */
1068
1069
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
5 len = (size_t)net_field_length_ll_safe(mysql, &pos, length,
1070 &is_error);
1071 if (is_error) return;
1072 pos += len;
1073 break;
1074 }
1075 441486 total_len -= (pos - saved_pos);
1076 }
1077
2/2
✓ Branch 0 taken 415796 times.
✓ Branch 1 taken 863 times.
416659 if (info) {
1078 int itype;
1079
2/2
✓ Branch 0 taken 2494768 times.
✓ Branch 1 taken 415796 times.
2910564 for (itype = SESSION_TRACK_BEGIN; itype <= SESSION_TRACK_END;
1080 itype++) {
1081
2/2
✓ Branch 0 taken 415910 times.
✓ Branch 1 taken 2078858 times.
2494768 if (info->info_list[itype].head_node) {
1082 415910 info->info_list[itype].current_node =
1083 415910 info->info_list[itype].head_node =
1084
1/2
✓ Branch 0 taken 415910 times.
✗ Branch 1 not taken.
415910 list_reverse(info->info_list[itype].head_node);
1085 }
1086 }
1087 }
1088 }
1089 }
1090 } else if (pos < mysql->net.read_pos + length && net_field_length(&pos))
1091 mysql->info = (char *)pos;
1092 else
1093 mysql->info = nullptr;
1094 12958630 return;
1095 }
1096
1097 /* Helper for cli_safe_read and cli_safe_read_nonblocking */
1098 static ulong cli_safe_read_with_ok_complete(MYSQL *mysql, bool parse_ok,
1099 bool *is_data_packet, ulong len);
1100
1101 /**
1102 Read a packet from server in asynchronous way. This function can return
1103 without completely reading the packet, in such a case call this function
1104 again until complete packet is read.
1105
1106 @param[in] mysql connection handle
1107 @param[in] parse_ok if set to true then parse OK packet if it
1108 was sent by server
1109 @param[out] is_data_packet if set to true then the packet received
1110 was a "data packet".
1111 @param[out] res The length of the packet that was read or
1112 packet_error in case of error.
1113
1114 @retval NET_ASYNC_NOT_READY packet was not completely read
1115 @retval NET_ASYNC_COMPLETE finished reading packet
1116 */
1117 30737595 net_async_status cli_safe_read_with_ok_nonblocking(MYSQL *mysql, bool parse_ok,
1118 bool *is_data_packet,
1119 ulong *res) {
1120 30737595 NET *net = &mysql->net;
1121 30737595 ulong len = 0;
1122
1/2
✓ Branch 0 taken 30737595 times.
✗ Branch 1 not taken.
30737595 DBUG_TRACE;
1123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30737595 times.
30737595 assert(net->vio);
1124
1125
3/4
✓ Branch 0 taken 30737595 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30735371 times.
✓ Branch 3 taken 2224 times.
30737595 if (NET_ASYNC_NOT_READY == my_net_read_nonblocking(net, &len)) {
1126 30735371 return NET_ASYNC_NOT_READY;
1127 }
1128
1129
3/8
✓ Branch 0 taken 2224 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2224 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2224 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2224 DBUG_PRINT("info",
1130 ("total nb read: %lu, net->where_b: %lu", len, net->where_b));
1131
1132
1/2
✓ Branch 0 taken 2224 times.
✗ Branch 1 not taken.
2224 *res = cli_safe_read_with_ok_complete(mysql, parse_ok, is_data_packet, len);
1133
1134 /*
1135 In case, packet is too large or connection is lost, net_end() is called to
1136 free up net->extention. Thus return NET_ASYNC_ERROR.
1137 */
1138
4/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2218 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
2224 if ((*res == packet_error) && (NET_ASYNC_DATA(net) == nullptr)) {
1139 return NET_ASYNC_ERROR;
1140 }
1141 2224 return NET_ASYNC_COMPLETE;
1142 30737595 }
1143
1144 /**
1145 Its a non blocking version of cli_safe_read
1146 */
1147 30737595 net_async_status cli_safe_read_nonblocking(MYSQL *mysql, bool *is_data_packet,
1148 ulong *res) {
1149 30737595 return cli_safe_read_with_ok_nonblocking(mysql, false, is_data_packet, res);
1150 }
1151
1152 /**
1153 Read a packet from server. Give error message if socket was down
1154 or packet is an error message
1155
1156 @param[in] mysql connection handle
1157 @param[in] parse_ok if set to true then parse OK packet
1158 if it is received
1159 @param[out] is_data_packet
1160 if set to true then packet received is
1161 a "data packet", that is not OK or ERR
1162 packet or EOF in case of old servers
1163
1164 @return The length of the packet that was read or packet_error in
1165 case of error. In case of error its description is stored
1166 in mysql handle.
1167 */
1168
1169 148149741 ulong cli_safe_read_with_ok(MYSQL *mysql, bool parse_ok, bool *is_data_packet) {
1170
1/2
✓ Branch 0 taken 148149859 times.
✗ Branch 1 not taken.
148149741 DBUG_TRACE;
1171 148149859 NET *net = &mysql->net;
1172 148149859 ulong len = 0;
1173
1174
3/8
✓ Branch 0 taken 146576816 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 146576815 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
146576815 MYSQL_TRACE(READ_PACKET, mysql, ());
1175
1176
2/2
✓ Branch 0 taken 133536153 times.
✓ Branch 1 taken 14613706 times.
148149859 if (is_data_packet) *is_data_packet = false;
1177
1178
3/4
✓ Branch 0 taken 148149858 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 148149545 times.
✗ Branch 3 not taken.
148149859 if (net->vio != nullptr) len = my_net_read(net);
1179
1/2
✓ Branch 0 taken 148149696 times.
✗ Branch 1 not taken.
296299243 return cli_safe_read_with_ok_complete(mysql, parse_ok, is_data_packet, len);
1180 148149696 }
1181
1182 148151774 ulong cli_safe_read_with_ok_complete(MYSQL *mysql, bool parse_ok,
1183 bool *is_data_packet, ulong len) {
1184 148151774 NET *net = &mysql->net;
1185
1/2
✓ Branch 0 taken 148151929 times.
✗ Branch 1 not taken.
148151774 DBUG_TRACE;
1186
1187
4/4
✓ Branch 0 taken 148135151 times.
✓ Branch 1 taken 16778 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 148135110 times.
148151929 if (len == packet_error || len == 0) {
1188 #ifndef NDEBUG
1189 char desc[VIO_DESCRIPTION_SIZE];
1190
1/2
✓ Branch 0 taken 16777 times.
✗ Branch 1 not taken.
16819 vio_description(net->vio, desc);
1191
3/8
✓ Branch 0 taken 16777 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16777 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16777 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
16777 DBUG_PRINT("error",
1192 ("Wrong connection or packet. fd: %s len: %lu", desc, len));
1193 #endif // NDEBUG
1194 #ifdef MYSQL_SERVER
1195
3/4
✓ Branch 0 taken 6473 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 6471 times.
6473 if (net->vio && (net->last_errno == ER_NET_READ_INTERRUPTED))
1196 2 return packet_error;
1197 #endif /*MYSQL_SERVER*/
1198
1/2
✓ Branch 0 taken 16775 times.
✗ Branch 1 not taken.
16775 end_server(mysql);
1199
1/2
✓ Branch 0 taken 16775 times.
✗ Branch 1 not taken.
16775 set_mysql_error(mysql,
1200
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 16772 times.
16775 net->last_errno == ER_NET_PACKET_TOO_LARGE
1201 ? CR_NET_PACKET_TOO_LARGE
1202 : CR_SERVER_LOST,
1203 unknown_sqlstate);
1204 16775 return packet_error;
1205 }
1206
1207
2/8
✓ Branch 0 taken 146568696 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 146568721 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
146568685 MYSQL_TRACE(PACKET_RECEIVED, mysql, (len, net->read_pos));
1208
1209
2/2
✓ Branch 0 taken 92361 times.
✓ Branch 1 taken 148042785 times.
148135146 if (net->read_pos[0] == 255) {
1210 /*
1211 After server reprts an error, usually it is ready to accept new commands
1212 and we set stage to READY_FOR_COMMAND. This can be modified by the caller
1213 of cli_safe_read().
1214 */
1215
2/10
✓ Branch 0 taken 91724 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 91724 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
91724 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1216
1217
1/2
✓ Branch 0 taken 92361 times.
✗ Branch 1 not taken.
92361 if (len > 3) {
1218 92361 uchar *pos = net->read_pos + 1;
1219 92361 net->last_errno = uint2korr(pos);
1220 92361 pos += 2;
1221 92361 len -= 2;
1222
4/4
✓ Branch 0 taken 92184 times.
✓ Branch 1 taken 177 times.
✓ Branch 2 taken 92164 times.
✓ Branch 3 taken 20 times.
92361 if (protocol_41(mysql) && pos[0] == '#') {
1223
1/2
✓ Branch 0 taken 92163 times.
✗ Branch 1 not taken.
92164 strmake(net->sqlstate, (char *)pos + 1, SQLSTATE_LENGTH);
1224 92163 pos += SQLSTATE_LENGTH + 1;
1225 } else {
1226 /*
1227 The SQL state hasn't been received -- it should be reset to HY000
1228 (unknown error sql state).
1229 */
1230
1231 197 my_stpcpy(net->sqlstate, unknown_sqlstate);
1232 }
1233
1234
1/2
✓ Branch 0 taken 92361 times.
✗ Branch 1 not taken.
92360 (void)strmake(net->last_error, (char *)pos,
1235 184721 std::min<ulong>(len, sizeof(net->last_error) - 1));
1236 } else
1237 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
1238 /*
1239 Cover a protocol design error: error packet does not
1240 contain the server status. Therefore, the client has no way
1241 to find out whether there are more result sets of
1242 a multiple-result-set statement pending. Luckily, in 5.0 an
1243 error always aborts execution of a statement, wherever it is
1244 a multi-statement or a stored procedure, so it should be
1245 safe to unconditionally turn off the flag here.
1246 */
1247 92361 mysql->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
1248
1249
3/8
✓ Branch 0 taken 92361 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 92361 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 92361 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
92361 DBUG_PRINT("error", ("Got error: %d/%s (%s)", net->last_errno,
1250 net->sqlstate, net->last_error));
1251 92361 return packet_error;
1252 } else {
1253 /* if it is OK packet irrespective of new/old server */
1254
2/2
✓ Branch 0 taken 6521245 times.
✓ Branch 1 taken 141521540 times.
148042785 if (net->read_pos[0] == 0) {
1255
2/2
✓ Branch 0 taken 13918 times.
✓ Branch 1 taken 6507327 times.
6521245 if (parse_ok) {
1256
1/2
✓ Branch 0 taken 13918 times.
✗ Branch 1 not taken.
13918 read_ok_ex(mysql, len);
1257 13918 return len;
1258 }
1259 }
1260 /*
1261 Now we have a data packet, unless it is OK packet starting with
1262 0xFE - we detect that case below.
1263 */
1264
2/2
✓ Branch 0 taken 133533973 times.
✓ Branch 1 taken 14494894 times.
148028867 if (is_data_packet) *is_data_packet = true;
1265 /*
1266 For a packet starting with 0xFE detect if it is OK packet or a
1267 huge data packet. Note that old servers do not send OK packets
1268 starting with 0xFE.
1269 */
1270
2/2
✓ Branch 0 taken 147860741 times.
✓ Branch 1 taken 168126 times.
148028867 if ((mysql->server_capabilities & CLIENT_DEPRECATE_EOF) &&
1271
2/2
✓ Branch 0 taken 9039303 times.
✓ Branch 1 taken 138821438 times.
147860741 (net->read_pos[0] == 254)) {
1272 /* detect huge data packet */
1273
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 9039258 times.
9039303 if (len > MAX_PACKET_LENGTH) return len;
1274 /* otherwise we have OK packet starting with 0xFE */
1275
2/2
✓ Branch 0 taken 9036136 times.
✓ Branch 1 taken 3122 times.
9039258 if (is_data_packet) *is_data_packet = false;
1276 /* parse it if requested */
1277
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9039257 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
9039258 if (parse_ok) read_ok_ex(mysql, len);
1278 9039258 return len;
1279 }
1280 /* for old client detect EOF packet */
1281
2/2
✓ Branch 0 taken 168119 times.
✓ Branch 1 taken 138821445 times.
138989564 if (!(mysql->server_capabilities & CLIENT_DEPRECATE_EOF) &&
1282
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 168119 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
168119 (net->read_pos[0] == 254) && (len < 8)) {
1283 if (is_data_packet) *is_data_packet = false;
1284 }
1285 }
1286 138989564 return len;
1287 148151923 }
1288
1289 /**
1290 Read a packet from server. Give error message if connection was broken or
1291 ERR packet was received. Detect if the packet received was an OK, ERR or
1292 something else (a "data packet").
1293
1294 @param[in] mysql connection handle
1295 @param[out] is_data_packet
1296 if set to true then the packet received
1297 was a "data packet".
1298
1299 @retval The length of the packet that was read or packet_error in case of
1300 error. In case of error its description is stored in mysql handle.
1301 */
1302 148135562 ulong cli_safe_read(MYSQL *mysql, bool *is_data_packet) {
1303 148135562 return cli_safe_read_with_ok(mysql, false, is_data_packet);
1304 }
1305
1306 9034084 void free_rows(MYSQL_DATA *cur) {
1307
2/2
✓ Branch 0 taken 8959110 times.
✓ Branch 1 taken 74974 times.
9034084 if (cur) {
1308 8959110 cur->alloc->Clear();
1309 8959110 my_free(cur->alloc);
1310 8959110 my_free(cur);
1311 }
1312 9034084 }
1313
1314 12274594 bool cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
1315 const uchar *header, size_t header_length,
1316 const uchar *arg, size_t arg_length, bool skip_check,
1317 MYSQL_STMT *stmt) {
1318 12274594 NET *net = &mysql->net;
1319 12274594 bool result = true;
1320
4/4
✓ Branch 0 taken 14104 times.
✓ Branch 1 taken 12260490 times.
✓ Branch 2 taken 10210 times.
✓ Branch 3 taken 3894 times.
12274594 bool stmt_skip = stmt ? stmt->state != MYSQL_STMT_INIT_DONE : false;
1321
1/2
✓ Branch 0 taken 12274674 times.
✗ Branch 1 not taken.
12274594 DBUG_TRACE;
1322
1323
4/4
✓ Branch 0 taken 12274662 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 12274641 times.
12274674 if (mysql->net.vio == nullptr || net->error == NET_ERROR_SOCKET_UNUSABLE) {
1324 /* Do reconnect if possible */
1325
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 8 times.
33 if (!mysql->reconnect) return true;
1326
6/8
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 5 times.
8 if (mysql_reconnect(mysql) || stmt_skip) return true; // reconnect failed
1327 /* reconnect succeeded */
1328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 assert(mysql->net.vio != nullptr);
1329 }
1330
1331 /* turn off non blocking operations */
1332
3/4
✓ Branch 0 taken 12274636 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 12274620 times.
12274646 if (!vio_is_blocking(mysql->net.vio))
1333
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 vio_set_blocking_flag(mysql->net.vio, true);
1334
1335
2/2
✓ Branch 0 taken 12274600 times.
✓ Branch 1 taken 36 times.
12274636 if (mysql->status != MYSQL_STATUS_READY ||
1336
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 12274587 times.
12274600 mysql->server_status & SERVER_MORE_RESULTS_EXISTS) {
1337
3/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
49 DBUG_PRINT("error", ("state: %d", mysql->status));
1338
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
1339 2 return true;
1340 }
1341
1342
1/2
✓ Branch 0 taken 12274596 times.
✗ Branch 1 not taken.
12274587 net_clear_error(net);
1343 12274596 mysql->info = nullptr;
1344 12274596 mysql->affected_rows = ~(my_ulonglong)0;
1345 /*
1346 Do not check the socket/protocol buffer as the
1347 result/error/timeout of a previous command might not have been read.
1348 This can happen if a client sends a query but does not reap the result
1349 before attempting to close the connection or wait_timeout occurs on
1350 the server.
1351 */
1352
1/2
✓ Branch 0 taken 12274626 times.
✗ Branch 1 not taken.
12274596 net_clear(&mysql->net, false);
1353
1354
2/10
✓ Branch 0 taken 12194923 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12194923 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
12194921 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1355
4/8
✓ Branch 0 taken 12194878 times.
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12194872 times.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
12194923 MYSQL_TRACE(SEND_COMMAND, mysql,
1356 (command, header_length, arg_length, header, arg));
1357
1358 /*
1359 If auto-reconnect mode is enabled check if connection is still alive before
1360 sending new command. Otherwise, send() might not notice that connection was
1361 closed by the server (for example, due to KILL statement), and the fact that
1362 connection is gone will be noticed only on attempt to read command's result,
1363 when it is too late to reconnect. Note that such scenario can still occur if
1364 connection gets killed after this check but before command is sent to
1365 server. But this should be rare.
1366 */
1367
9/10
✓ Branch 0 taken 12124349 times.
✓ Branch 1 taken 150228 times.
✓ Branch 2 taken 137242 times.
✓ Branch 3 taken 11987107 times.
✓ Branch 4 taken 137242 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4608 times.
✓ Branch 7 taken 132634 times.
✓ Branch 8 taken 4608 times.
✓ Branch 9 taken 12269969 times.
12274577 if ((command != COM_QUIT) && mysql->reconnect && !vio_is_connected(net->vio))
1368 4608 net->error = NET_ERROR_SOCKET_UNUSABLE;
1369
1370
3/4
✓ Branch 0 taken 12274619 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11957 times.
✓ Branch 3 taken 12262662 times.
12274577 if (net_write_command(net, (uchar)command, header, header_length, arg,
1371 arg_length)) {
1372
3/8
✓ Branch 0 taken 11957 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11957 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11957 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
11957 DBUG_PRINT("error",
1373 ("Can't send command to server. Error: %d", socket_errno));
1374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11957 times.
11957 if (net->last_errno == ER_NET_PACKET_TOO_LARGE) {
1375 set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate);
1376 goto end;
1377 }
1378
2/2
✓ Branch 0 taken 7347 times.
✓ Branch 1 taken 4610 times.
11957 if (net->last_errno == ER_NET_ERROR_ON_WRITE) {
1379 /*
1380 Write error, try to read and see if the server gave an error
1381 before closing the connection. Most likely Unix Domain Socket.
1382 */
1383
1/2
✓ Branch 0 taken 7347 times.
✗ Branch 1 not taken.
7347 if (net->vio) {
1384
1/2
✓ Branch 0 taken 7347 times.
✗ Branch 1 not taken.
7347 my_net_set_read_timeout(net, 1);
1385 /*
1386 cli_safe_read will also set error variables in net,
1387 and we are already in error state.
1388 */
1389
3/4
✓ Branch 0 taken 7347 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7261 times.
✓ Branch 3 taken 86 times.
7347 if (cli_safe_read(mysql, nullptr) == packet_error) {
1390
2/2
✓ Branch 0 taken 7259 times.
✓ Branch 1 taken 2 times.
7261 if (!mysql->reconnect) goto end;
1391 }
1392 /* Can this happen in any other case than COM_QUIT? */
1393
3/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
88 if (!mysql->reconnect) assert(command == COM_QUIT);
1394 }
1395 }
1396
1/2
✓ Branch 0 taken 4698 times.
✗ Branch 1 not taken.
4698 end_server(mysql);
1397
6/8
✓ Branch 0 taken 4698 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3846 times.
✓ Branch 3 taken 852 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3846 times.
✓ Branch 6 taken 852 times.
✓ Branch 7 taken 3846 times.
4698 if (mysql_reconnect(mysql) || stmt_skip) goto end;
1398
1399
2/8
✓ Branch 0 taken 3844 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3844 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3844 MYSQL_TRACE(SEND_COMMAND, mysql,
1400 (command, header_length, arg_length, header, arg));
1401
2/4
✓ Branch 0 taken 3846 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3846 times.
3846 if (net_write_command(net, (uchar)command, header, header_length, arg,
1402 arg_length)) {
1403 set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
1404 goto end;
1405 }
1406 }
1407
1408
3/8
✓ Branch 0 taken 12186860 times.
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12186865 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
12186895 MYSQL_TRACE(PACKET_SENT, mysql, (header_length + arg_length));
1409
1410 #if defined(CLIENT_PROTOCOL_TRACING)
1411
7/7
✓ Branch 0 taken 3877 times.
✓ Branch 1 taken 1588 times.
✓ Branch 2 taken 147685 times.
✓ Branch 3 taken 163 times.
✓ Branch 4 taken 243 times.
✓ Branch 5 taken 28 times.
✓ Branch 6 taken 12033281 times.
12186865 switch (command) {
1412 3877 case COM_STMT_PREPARE:
1413
2/10
✓ Branch 0 taken 3877 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3877 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
3877 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_PS_DESCRIPTION);
1414 3877 break;
1415
1416 1588 case COM_STMT_FETCH:
1417
2/10
✓ Branch 0 taken 1588 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1588 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1588 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_ROW);
1418 1588 break;
1419
1420 /*
1421 No server reply is expected after these commands so we reamin
1422 ready for the next command.
1423 */
1424 147685 case COM_STMT_SEND_LONG_DATA:
1425 case COM_STMT_CLOSE:
1426 case COM_REGISTER_SLAVE:
1427 case COM_QUIT:
1428 147685 break;
1429
1430 /*
1431 These replication commands are not supported and we bail out
1432 by pretending that connection has been closed.
1433 */
1434 163 case COM_BINLOG_DUMP:
1435 case COM_BINLOG_DUMP_GTID:
1436 case COM_TABLE_DUMP:
1437
2/8
✓ Branch 0 taken 163 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 163 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
163 MYSQL_TRACE(DISCONNECTED, mysql, ());
1438 163 break;
1439
1440 /*
1441 After COM_CHANGE_USER a regular authentication exchange
1442 is performed.
1443 */
1444 243 case COM_CHANGE_USER:
1445
2/10
✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 243 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
243 MYSQL_TRACE_STAGE(mysql, AUTHENTICATE);
1446 243 break;
1447
1448 /*
1449 Server replies to COM_STATISTICS with a single packet
1450 containing a string with statistics information.
1451 */
1452 28 case COM_STATISTICS:
1453
2/10
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
28 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_PACKET);
1454 28 break;
1455
1456 /*
1457 For all other commands we expect server to send regular reply
1458 which is either OK, ERR or a result-set header.
1459 */
1460 12033281 default:
1461
2/10
✓ Branch 0 taken 12033281 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12033281 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
12033281 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
1462 12033281 break;
1463 }
1464 #endif
1465
1466 12266478 result = false;
1467
2/2
✓ Branch 0 taken 12252291 times.
✓ Branch 1 taken 14187 times.
12266478 if (!skip_check) {
1468 14189 result = ((mysql->packet_length =
1469
1/2
✓ Branch 0 taken 14189 times.
✗ Branch 1 not taken.
14187 cli_safe_read_with_ok(mysql, true, nullptr)) == packet_error
1470 ? 1
1471 : 0);
1472
1473 #if defined(CLIENT_PROTOCOL_TRACING)
1474 /*
1475 Return to READY_FOR_COMMAND protocol stage in case server reports error
1476 or sends OK packet.
1477 */
1478
4/4
✓ Branch 0 taken 3050 times.
✓ Branch 1 taken 73 times.
✓ Branch 2 taken 3019 times.
✓ Branch 3 taken 31 times.
3123 if (result || mysql->net.read_pos[0] == 0x00)
1479
2/10
✓ Branch 0 taken 3092 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3092 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
3092 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1480 #endif
1481 }
1482
1483 12252291 end:
1484
3/8
✓ Branch 0 taken 12274581 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12274609 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12274609 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
12274591 DBUG_PRINT("exit", ("result: %d", result));
1485 12274621 return result;
1486 12274651 }
1487
1488 7207 net_async_status cli_advanced_command_nonblocking(
1489 MYSQL *mysql, enum enum_server_command command, const uchar *header,
1490 ulong header_length, const uchar *arg, ulong arg_length, bool skip_check,
1491 MYSQL_STMT *stmt, bool *ret) {
1492 7207 NET *net = &mysql->net;
1493
2/2
✓ Branch 0 taken 6759 times.
✓ Branch 1 taken 448 times.
7207 NET_ASYNC *net_async = NET_ASYNC_DATA(net);
1494 7207 bool result = true;
1495 7207 *ret = result;
1496
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7207 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
7207 bool stmt_skip = stmt ? stmt->state != MYSQL_STMT_INIT_DONE : false;
1497
1/2
✓ Branch 0 taken 7207 times.
✗ Branch 1 not taken.
7207 DBUG_TRACE;
1498
1/2
✓ Branch 0 taken 7207 times.
✗ Branch 1 not taken.
7207 DBUG_DUMP("sending", header, header_length);
1499
3/4
✓ Branch 0 taken 6724 times.
✓ Branch 1 taken 483 times.
✓ Branch 2 taken 6724 times.
✗ Branch 3 not taken.
7207 if (arg && arg_length) {
1500
1/2
✓ Branch 0 taken 6724 times.
✗ Branch 1 not taken.
6724 DBUG_DUMP("sending arg", arg, arg_length);
1501 }
1502
1503
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7207 times.
7207 if (mysql->net.vio == nullptr) {
1504 set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
1505 goto end;
1506 }
1507 /**
1508 When non blocking API execution is pending and did not complete then
1509 it can result in async context to be null. In such case if user executes
1510 any other API report command out of sync error.
1511 */
1512
2/2
✓ Branch 0 taken 448 times.
✓ Branch 1 taken 6759 times.
7207 if (net_async == nullptr) {
1513
1/2
✓ Branch 0 taken 448 times.
✗ Branch 1 not taken.
448 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
1514 448 goto end;
1515 }
1516
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 6575 times.
6759 if (net_async->async_send_command_status == NET_ASYNC_SEND_COMMAND_IDLE) {
1517
3/4
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 171 times.
184 if (vio_is_blocking(mysql->net.vio)) {
1518
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 vio_set_blocking_flag(net->vio, false);
1519 }
1520
1521
1/2
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
184 if (mysql->status != MYSQL_STATUS_READY ||
1522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 184 times.
184 mysql->server_status & SERVER_MORE_RESULTS_EXISTS) {
1523 DBUG_PRINT("error", ("state: %d", mysql->status));
1524 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
1525 return NET_ASYNC_COMPLETE;
1526 }
1527
1528
1/2
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
184 net_clear_error(net);
1529 184 mysql->info = nullptr;
1530 184 mysql->affected_rows = ~(my_ulonglong)0;
1531 /*
1532 Do not check the socket/protocol buffer on COM_QUIT as the
1533 result of a previous command might not have been read. This
1534 can happen if a client sends a query but does not reap
1535 the result before attempting to close the connection.
1536 */
1537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 184 times.
184 assert(command <= COM_END);
1538
1/2
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
184 net_clear(&mysql->net, false);
1539 184 net_async->async_send_command_status = NET_ASYNC_SEND_COMMAND_WRITE_COMMAND;
1540 }
1541
1542
2/10
✓ Branch 0 taken 6759 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6759 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
6759 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1543
1/2
✓ Branch 0 taken 6759 times.
✗ Branch 1 not taken.
6759 if (net_async->async_send_command_status ==
1544 NET_ASYNC_SEND_COMMAND_WRITE_COMMAND) {
1545 bool err;
1546
2/8
✓ Branch 0 taken 6759 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 6759 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
6759 MYSQL_TRACE(SEND_COMMAND, mysql,
1547 (command, header_length, arg_length, header, arg));
1548
1/2
✓ Branch 0 taken 6759 times.
✗ Branch 1 not taken.
6759 net_async_status status = net_write_command_nonblocking(
1549 net, (uchar)command, header, header_length, arg, arg_length, &err);
1550
2/2
✓ Branch 0 taken 6575 times.
✓ Branch 1 taken 184 times.
6759 if (status == NET_ASYNC_NOT_READY) {
1551 6575 return NET_ASYNC_NOT_READY;
1552 }
1553
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 183 times.
184 if (err) {
1554
3/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 DBUG_PRINT("error",
1555 ("Can't send command to server. Error: %d", socket_errno));
1556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (net->last_errno == ER_NET_PACKET_TOO_LARGE) {
1557 set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate);
1558 184 goto end;
1559 }
1560
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 end_server(mysql);
1561 /* reset net_async to null as its reference has been freed */
1562 1 net_async = nullptr;
1563
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stmt_skip) goto end;
1564
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
1565 1 goto end;
1566 }
1567
2/8
✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 183 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
183 MYSQL_TRACE(PACKET_SENT, mysql, (header_length + arg_length));
1568
1/2
✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
183 if (skip_check) {
1569 183 result = false;
1570 183 goto end;
1571 } else {
1572 net_async->async_send_command_status = NET_ASYNC_SEND_COMMAND_READ_STATUS;
1573 }
1574 }
1575
1576 if (net_async->async_send_command_status ==
1577 NET_ASYNC_SEND_COMMAND_READ_STATUS) {
1578 ulong pkt_len;
1579 net_async_status status =
1580 cli_safe_read_with_ok_nonblocking(mysql, true, nullptr, &pkt_len);
1581 if (status == NET_ASYNC_NOT_READY) {
1582 return NET_ASYNC_NOT_READY;
1583 }
1584 mysql->packet_length = pkt_len;
1585 result = (pkt_len == packet_error ? 1 : 0);
1586 #if defined(CLIENT_PROTOCOL_TRACING)
1587 /*
1588 Return to READY_FOR_COMMAND protocol stage in case server reports
1589 error or sends OK packet.
1590 */
1591 if (!result || mysql->net.read_pos[0] == 0x00)
1592 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1593 #endif
1594 }
1595 end:
1596
2/2
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 449 times.
632 if (net_async)
1597 183 net_async->async_send_command_status = NET_ASYNC_SEND_COMMAND_IDLE;
1598
3/8
✓ Branch 0 taken 632 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 632 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 632 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
632 DBUG_PRINT("exit", ("result: %d", result));
1599 632 *ret = result;
1600 632 return NET_ASYNC_COMPLETE;
1601 7207 }
1602
1603 13415897 void free_old_query(MYSQL *mysql) {
1604
1/2
✓ Branch 0 taken 13416045 times.
✗ Branch 1 not taken.
13415897 DBUG_TRACE;
1605
2/2
✓ Branch 0 taken 13415628 times.
✓ Branch 1 taken 417 times.
13416045 if (mysql->field_alloc) {
1606
1/2
✓ Branch 0 taken 13415622 times.
✗ Branch 1 not taken.
13415628 mysql->field_alloc->Clear();
1607 }
1608 13416039 mysql->fields = nullptr;
1609 13416039 mysql->field_count = 0; /* For API */
1610 13416039 mysql->warning_count = 0;
1611 13416039 mysql->info = nullptr;
1612 13416039 }
1613
1614 /**
1615 Finish reading of a partial result set from the server in asynchronous
1616 way. This function can return without completely flushing the result set,
1617 in such a case call this function again until result set in flushed.
1618 Read OK packet in case result set is not a data packet.
1619
1620 @param[in] mysql connection handle
1621 @param[out] res true in case of protocol error, false otherwise
1622
1623 @retval NET_ASYNC_NOT_READY result set not flushed yet
1624 @retval NET_ASYNC_COMPLETE finished flushing result set
1625 */
1626 4463 static net_async_status flush_one_result_nonblocking(MYSQL *mysql, bool *res) {
1627
1/2
✓ Branch 0 taken 4463 times.
✗ Branch 1 not taken.
4463 DBUG_TRACE;
1628
1629 4463 *res = false;
1630 while (true) {
1631 ulong packet_length;
1632 bool is_data_packet;
1633
3/4
✓ Branch 0 taken 5999 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4462 times.
✓ Branch 3 taken 1537 times.
5999 if (cli_safe_read_nonblocking(mysql, &is_data_packet, &packet_length) ==
1634 NET_ASYNC_NOT_READY) {
1635 4462 return NET_ASYNC_NOT_READY;
1636 }
1637 1537 mysql->packet_length = packet_length;
1638
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1537 times.
1537 if (packet_length == packet_error) {
1639 *res = true;
1640 break;
1641 }
1642
3/4
✓ Branch 0 taken 1537 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1536 times.
1537 if (mysql->net.read_pos[0] != 0 && !is_data_packet) {
1643
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (protocol_41(mysql)) {
1644 1 uchar *pos = mysql->net.read_pos + 1;
1645
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (mysql->server_capabilities & CLIENT_DEPRECATE_EOF &&
1646
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !is_data_packet) {
1647
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 read_ok_ex(mysql, packet_length);
1648 } else {
1649 mysql->warning_count = uint2korr(pos);
1650 pos += 2;
1651 mysql->server_status = uint2korr(pos);
1652 }
1653 1 pos += 2;
1654 }
1655 1 break;
1656 }
1657 1536 }
1658 1 return NET_ASYNC_COMPLETE;
1659 4463 }
1660
1661 /**
1662 Finish reading of a partial result set from the server.
1663 Get the EOF packet, and update mysql->status
1664 and mysql->warning_count.
1665
1666 @return true if a communication or protocol error, an error
1667 is set in this case, false otherwise.
1668 */
1669
1670 30379 static bool flush_one_result(MYSQL *mysql) {
1671 ulong packet_length;
1672 bool is_data_packet;
1673
1674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30379 times.
30379 assert(mysql->status != MYSQL_STATUS_READY);
1675
1676 do {
1677
1/2
✓ Branch 0 taken 30531 times.
✗ Branch 1 not taken.
30531 packet_length = cli_safe_read(mysql, &is_data_packet);
1678 /*
1679 There is an error reading from the connection,
1680 or (sic!) there were no error and no
1681 data in the stream, i.e. no more data from the server.
1682 Since we know our position in the stream (somewhere in
1683 the middle of a result set), this latter case is an error too
1684 -- each result set must end with a EOF packet.
1685 cli_safe_read() has set an error for us, just return.
1686 */
1687
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30531 times.
30531 if (packet_length == packet_error) return true;
1688
4/4
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 30384 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 30379 times.
30531 } while (mysql->net.read_pos[0] == 0 || is_data_packet);
1689
1690 /* Analyse final OK packet (EOF packet if it is old client) */
1691
1692
1/2
✓ Branch 0 taken 30379 times.
✗ Branch 1 not taken.
30379 if (protocol_41(mysql)) {
1693 30379 uchar *pos = mysql->net.read_pos + 1;
1694
2/4
✓ Branch 0 taken 30379 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30379 times.
✗ Branch 3 not taken.
30379 if (mysql->server_capabilities & CLIENT_DEPRECATE_EOF && !is_data_packet)
1695
1/2
✓ Branch 0 taken 30379 times.
✗ Branch 1 not taken.
30379 read_ok_ex(mysql, packet_length);
1696 else {
1697 mysql->warning_count = uint2korr(pos);
1698 pos += 2;
1699 mysql->server_status = uint2korr(pos);
1700 }
1701 30379 pos += 2;
1702 }
1703 #if defined(CLIENT_PROTOCOL_TRACING)
1704
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 30346 times.
30379 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
1705
2/10
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 33 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
33 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
1706 else
1707
2/10
✓ Branch 0 taken 30346 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30346 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
30346 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1708 #endif
1709 30379 return false;
1710 }
1711
1712 166834 static bool is_OK_packet(MYSQL *mysql, ulong length) {
1713
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 166814 times.
166854 return ((mysql->net.read_pos[0] == 0) ||
1714
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 ((mysql->server_capabilities & CLIENT_DEPRECATE_EOF) &&
1715
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
166854 mysql->net.read_pos[0] == 254 && length < MAX_PACKET_LENGTH));
1716 }
1717
1718 /**
1719 Helper method to check if received packet is AuthNextFactor packet.
1720
1721 @param[in] mysql connection handle
1722
1723 @retval true packet is AuthNextFactor packet
1724 @retval false if its not AuthNextFactor packet
1725 */
1726 166801 static bool is_auth_next_factor_packet(MYSQL *mysql) {
1727
2/2
✓ Branch 0 taken 161240 times.
✓ Branch 1 taken 5561 times.
328041 return ((mysql->server_capabilities & MULTI_FACTOR_AUTHENTICATION) &&
1728
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 161240 times.
328041 (mysql->net.read_pos[0] == AUTH_NEXT_FACTOR_PACKETTYPE));
1729 }
1730 /**
1731 Read a packet from network. If it's an OK packet, flush it.
1732
1733 @return true if error, false otherwise. In case of
1734 success, is_ok_packet is set to true or false,
1735 based on what we got from network.
1736 */
1737
1738 30 static bool opt_flush_ok_packet(MYSQL *mysql, bool *is_ok_packet) {
1739 bool is_data_packet;
1740
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 ulong packet_length = cli_safe_read(mysql, &is_data_packet);
1741
1742
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (packet_length == packet_error) return true;
1743
1744 /* cli_safe_read always reads a non-empty packet. */
1745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 assert(packet_length);
1746
1747 30 *is_ok_packet = is_OK_packet(mysql, packet_length);
1748
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 20 times.
30 if (*is_ok_packet) {
1749
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 read_ok_ex(mysql, packet_length);
1750 #if defined(CLIENT_PROTOCOL_TRACING)
1751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
1752 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
1753 else
1754
2/10
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
10 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1755 #endif
1756 }
1757
1758 30 return false;
1759 }
1760
1761 4463 static net_async_status cli_flush_use_result_nonblocking(MYSQL *mysql,
1762 bool flush_all_results
1763 [[maybe_unused]]) {
1764
1/2
✓ Branch 0 taken 4463 times.
✗ Branch 1 not taken.
4463 DBUG_TRACE;
1765 /*
1766 flush_all_results is only used for mysql_stmt_close, and async is not
1767 supported for that.
1768 */
1769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4463 times.
4463 assert(!flush_all_results);
1770 bool res;
1771
1/2
✓ Branch 0 taken 4463 times.
✗ Branch 1 not taken.
8926 return flush_one_result_nonblocking(mysql, &res);
1772 4463 }
1773
1774 /*
1775 Flush result set sent from server
1776 */
1777
1778 30359 static void cli_flush_use_result(MYSQL *mysql, bool flush_all_results) {
1779 /* Clear the current execution status */
1780
1/2
✓ Branch 0 taken 30359 times.
✗ Branch 1 not taken.
30359 DBUG_TRACE;
1781
3/8
✓ Branch 0 taken 30359 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30359 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30359 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
30359 DBUG_PRINT("warning", ("Not all packets read, clearing them"));
1782
1783
2/4
✓ Branch 0 taken 30359 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30359 times.
30359 if (flush_one_result(mysql)) return; /* An error occurred */
1784
1785
2/2
✓ Branch 0 taken 30286 times.
✓ Branch 1 taken 73 times.
30359 if (!flush_all_results) return;
1786
1787
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 63 times.
93 while (mysql->server_status & SERVER_MORE_RESULTS_EXISTS) {
1788 bool is_ok_packet;
1789
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
30 if (opt_flush_ok_packet(mysql, &is_ok_packet))
1790 10 return; /* An error occurred. */
1791
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 20 times.
30 if (is_ok_packet) {
1792 /*
1793 Indeed what we got from network was an OK packet, and we
1794 know that OK is the last one in a multi-result-set, so
1795 just return.
1796 */
1797 10 return;
1798 }
1799
1800 /*
1801 It's a result set, not an OK packet. A result set contains
1802 of two result set subsequences: field metadata, terminated
1803 with EOF packet, and result set data, again terminated with
1804 EOF packet. Read and flush them.
1805 */
1806
2/10
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
20 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_FIELD_DEF);
1807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (!(mysql->server_capabilities & CLIENT_DEPRECATE_EOF)) {
1808 if (flush_one_result(mysql)) return; /* An error occurred. */
1809 } else {
1810 20 uchar *pos = (uchar *)mysql->net.read_pos;
1811
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 ulong field_count = net_field_length(&pos);
1812
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 if (read_com_query_metadata(mysql, pos, field_count)) {
1813 return;
1814 } else {
1815
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 mysql->field_alloc->Clear();
1816 }
1817 }
1818
2/10
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
20 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_ROW);
1819
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 if (flush_one_result(mysql)) return;
1820 }
1821
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 30296 times.
30359 }
1822
1823 #ifdef _WIN32
1824 static bool is_NT(void) {
1825 char *os = getenv("OS");
1826 return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
1827 }
1828 #endif
1829
1830 #ifdef CHECK_LICENSE
1831 /**
1832 Check server side variable 'license'.
1833
1834 If the variable does not exist or does not contain 'Commercial',
1835 we're talking to non-commercial server from commercial client.
1836
1837 @retval 0 success
1838 @retval !0 network error or the server is not commercial.
1839 Error code is saved in mysql->net.last_errno.
1840 */
1841
1842 static int check_license(MYSQL *mysql) {
1843 MYSQL_ROW row;
1844 MYSQL_RES *res;
1845 NET *net = &mysql->net;
1846 static const char query[] = "SELECT @@license";
1847 static const char required_license[] = STRINGIFY_ARG(LICENSE);
1848
1849 if (mysql_real_query(mysql, query, (ulong)(sizeof(query) - 1))) {
1850 if (net->last_errno == ER_UNKNOWN_SYSTEM_VARIABLE) {
1851 set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate,
1852 ER_CLIENT(CR_WRONG_LICENSE), required_license);
1853 }
1854 return 1;
1855 }
1856 if (!(res = mysql_use_result(mysql))) return 1;
1857 row = mysql_fetch_row(res);
1858 /*
1859 If no rows in result set, or column value is NULL (none of these
1860 two is ever true for server variables now), or column value
1861 mismatch, set wrong license error.
1862 */
1863 if (!net->last_errno &&
1864 (!row || !row[0] ||
1865 strncmp(row[0], required_license, sizeof(required_license)))) {
1866 set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate,
1867 ER_CLIENT(CR_WRONG_LICENSE), required_license);
1868 }
1869 mysql_free_result(res);
1870 return net->last_errno;
1871 }
1872 #endif /* CHECK_LICENSE */
1873
1874 /**************************************************************************
1875 Shut down connection
1876 **************************************************************************/
1877
1878 482664 void end_server(MYSQL *mysql) {
1879 482664 int save_errno = errno;
1880
1/2
✓ Branch 0 taken 482717 times.
✗ Branch 1 not taken.
482664 DBUG_TRACE;
1881
2/2
✓ Branch 0 taken 235016 times.
✓ Branch 1 taken 247701 times.
482717 if (mysql->net.vio != nullptr) {
1882 #ifndef NDEBUG
1883 char desc[VIO_DESCRIPTION_SIZE];
1884
1/2
✓ Branch 0 taken 234982 times.
✗ Branch 1 not taken.
235016 vio_description(mysql->net.vio, desc);
1885
3/8
✓ Branch 0 taken 235001 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 234994 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 234994 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
234982 DBUG_PRINT("info", ("Net: %s", desc));
1886 #endif // NDEBUG
1887 #ifdef MYSQL_SERVER
1888
1/2
✓ Branch 0 taken 10774 times.
✗ Branch 1 not taken.
10774 slave_io_thread_detach_vio();
1889 #endif
1890
1/2
✓ Branch 0 taken 234993 times.
✗ Branch 1 not taken.
234994 vio_delete(mysql->net.vio);
1891 234993 mysql->net.vio = nullptr; /* Marker */
1892
1/2
✓ Branch 0 taken 234960 times.
✗ Branch 1 not taken.
234993 mysql_prune_stmt_list(mysql);
1893 }
1894
1/2
✓ Branch 0 taken 482710 times.
✗ Branch 1 not taken.
482661 net_end(&mysql->net);
1895 // net_extension_free(&mysql->net);
1896
1/2
✓ Branch 0 taken 482709 times.
✗ Branch 1 not taken.
482710 free_old_query(mysql);
1897 482709 errno = save_errno;
1898
4/8
✓ Branch 0 taken 471774 times.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 471768 times.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
471792 MYSQL_TRACE(DISCONNECTED, mysql, ());
1899 482685 }
1900
1901 /**
1902 Frees the memory allocated for a result, set by APIs which would have
1903 returned rows.
1904
1905 @param[in] result buffer which needs to be freed
1906
1907 @retval NET_ASYNC_NOT_READY operation not complete, retry again
1908 @retval NET_ASYNC_COMPLETE operation complete
1909 */
1910 4598 net_async_status STDCALL mysql_free_result_nonblocking(MYSQL_RES *result) {
1911
1/2
✓ Branch 0 taken 4598 times.
✗ Branch 1 not taken.
4598 DBUG_TRACE;
1912
3/8
✓ Branch 0 taken 4598 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4598 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4598 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4598 DBUG_PRINT("enter", ("mysql_res: %p", result));
1913
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4595 times.
4598 if (!result) return NET_ASYNC_COMPLETE;
1914
1915 4595 MYSQL *mysql = result->handle;
1916
2/2
✓ Branch 0 taken 4463 times.
✓ Branch 1 taken 132 times.
4595 if (mysql) {
1917
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4462 times.
4463 if (mysql->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
1918 1 mysql->unbuffered_fetch_owner = nullptr;
1919
1/2
✓ Branch 0 taken 4463 times.
✗ Branch 1 not taken.
4463 if (mysql->status == MYSQL_STATUS_USE_RESULT) {
1920
3/4
✓ Branch 0 taken 4463 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4462 times.
✓ Branch 3 taken 1 times.
4463 if (mysql->methods->flush_use_result_nonblocking(mysql, false) ==
1921 NET_ASYNC_NOT_READY) {
1922 4462 return NET_ASYNC_NOT_READY;
1923 }
1924 1 mysql->status = MYSQL_STATUS_READY;
1925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (mysql->unbuffered_fetch_owner) *mysql->unbuffered_fetch_owner = true;
1926 }
1927 }
1928
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 free_rows(result->data);
1929
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 if (result->field_alloc) {
1930
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 result->field_alloc->Clear();
1931
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 my_free(result->field_alloc);
1932 }
1933
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 my_free(result->row);
1934
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 my_free(result);
1935
1936 133 return NET_ASYNC_COMPLETE;
1937 4598 }
1938
1939 9344895 void STDCALL mysql_free_result(MYSQL_RES *result) {
1940
1/2
✓ Branch 0 taken 9344898 times.
✗ Branch 1 not taken.
9344895 DBUG_TRACE;
1941
3/8
✓ Branch 0 taken 9344897 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9344898 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9344898 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
9344898 DBUG_PRINT("enter", ("mysql_res: %p", result));
1942
2/2
✓ Branch 0 taken 9033824 times.
✓ Branch 1 taken 311074 times.
9344898 if (result) {
1943 9033824 MYSQL *mysql = result->handle;
1944
2/2
✓ Branch 0 taken 30273 times.
✓ Branch 1 taken 9003551 times.
9033824 if (mysql) {
1945
1/2
✓ Branch 0 taken 30273 times.
✗ Branch 1 not taken.
30273 if (mysql->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
1946 30273 mysql->unbuffered_fetch_owner = nullptr;
1947
1/2
✓ Branch 0 taken 30273 times.
✗ Branch 1 not taken.
30273 if (mysql->status == MYSQL_STATUS_USE_RESULT) {
1948
1/2
✓ Branch 0 taken 30273 times.
✗ Branch 1 not taken.
30273 (*mysql->methods->flush_use_result)(mysql, false);
1949 30273 mysql->status = MYSQL_STATUS_READY;
1950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30273 times.
30273 if (mysql->unbuffered_fetch_owner)
1951 *mysql->unbuffered_fetch_owner = true;
1952 }
1953 }
1954
1/2
✓ Branch 0 taken 9033824 times.
✗ Branch 1 not taken.
9033824 free_rows(result->data);
1955
2/2
✓ Branch 0 taken 9032533 times.
✓ Branch 1 taken 1291 times.
9033824 if (result->field_alloc) {
1956
1/2
✓ Branch 0 taken 9032534 times.
✗ Branch 1 not taken.
9032533 result->field_alloc->Clear();
1957
1/2
✓ Branch 0 taken 9032534 times.
✗ Branch 1 not taken.
9032534 my_free(result->field_alloc);
1958 }
1959
1/2
✓ Branch 0 taken 9033824 times.
✗ Branch 1 not taken.
9033825 my_free(result->row);
1960
1/2
✓ Branch 0 taken 9033824 times.
✗ Branch 1 not taken.
9033824 my_free(result);
1961 }
1962 9344898 }
1963
1964 /****************************************************************************
1965 Get options from my.cnf
1966 ****************************************************************************/
1967
1968 static const char *default_options[] = {"port",
1969 "socket",
1970 "compress",
1971 "password",
1972 "pipe",
1973 "timeout",
1974 "user",
1975 "init-command",
1976 "host",
1977 "database",
1978 "debug",
1979 "return-found-rows",
1980 "ssl-key",
1981 "ssl-cert",
1982 "ssl-ca",
1983 "ssl-capath",
1984 "character-sets-dir",
1985 "default-character-set",
1986 "interactive-timeout",
1987 "connect-timeout",
1988 "local-infile",
1989 "disable-local-infile",
1990 "ssl-cipher",
1991 "max-allowed-packet",
1992 "protocol",
1993 "shared-memory-base-name",
1994 "multi-results",
1995 "multi-statements",
1996 "multi-queries",
1997 "report-data-truncation",
1998 "plugin-dir",
1999 "default-auth",
2000 "bind-address",
2001 "ssl-crl",
2002 "ssl-crlpath",
2003 "enable-cleartext-plugin",
2004 "tls-version",
2005 "ssl_mode",
2006 "optional-resultset-metadata",
2007 "ssl-fips-mode",
2008 "tls-ciphersuites",
2009 NullS};
2010 enum option_id {
2011 OPT_port = 1,
2012 OPT_socket,
2013 OPT_compress,
2014 OPT_password,
2015 OPT_pipe,
2016 OPT_timeout,
2017 OPT_user,
2018 OPT_init_command,
2019 OPT_host,
2020 OPT_database,
2021 OPT_debug,
2022 OPT_return_found_rows,
2023 OPT_ssl_key,
2024 OPT_ssl_cert,
2025 OPT_ssl_ca,
2026 OPT_ssl_capath,
2027 OPT_character_sets_dir,
2028 OPT_default_character_set,
2029 OPT_interactive_timeout,
2030 OPT_connect_timeout,
2031 OPT_local_infile,
2032 OPT_disable_local_infile,
2033 OPT_ssl_cipher,
2034 OPT_max_allowed_packet,
2035 OPT_protocol,
2036 OPT_shared_memory_base_name,
2037 OPT_multi_results,
2038 OPT_multi_statements,
2039 OPT_multi_queries,
2040 OPT_report_data_truncation,
2041 OPT_plugin_dir,
2042 OPT_default_auth,
2043 OPT_bind_address,
2044 OPT_ssl_crl,
2045 OPT_ssl_crlpath,
2046 OPT_enable_cleartext_plugin,
2047 OPT_tls_version,
2048 OPT_ssl_mode,
2049 OPT_optional_resultset_metadata,
2050 OPT_ssl_fips_mode,
2051 OPT_tls_ciphersuites,
2052 OPT_keep_this_one_last
2053 };
2054
2055 static TYPELIB option_types = {array_elements(default_options) - 1, "options",
2056 default_options, nullptr};
2057
2058 const char *sql_protocol_names_lib[] = {"TCP", "SOCKET", "PIPE", "MEMORY",
2059 NullS};
2060 TYPELIB sql_protocol_typelib = {array_elements(sql_protocol_names_lib) - 1, "",
2061 sql_protocol_names_lib, nullptr};
2062
2063 4 static int add_init_command(struct st_mysql_options *options, const char *cmd) {
2064 char *tmp;
2065
2066
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!options->init_commands) {
2067
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 void *rawmem = my_malloc(key_memory_mysql_options,
2068 sizeof(Init_commands_array), MYF(MY_WME));
2069
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!rawmem) return 1;
2070 4 options->init_commands =
2071
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 new (rawmem) Init_commands_array(key_memory_mysql_options);
2072 }
2073
2074
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
8 if (!(tmp = my_strdup(key_memory_mysql_options, cmd, MYF(MY_WME))) ||
2075
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 options->init_commands->push_back(tmp)) {
2076 my_free(tmp);
2077 return 1;
2078 }
2079
2080 4 return 0;
2081 }
2082
2083 805332 static char *set_ssl_option_unpack_path(const char *arg) {
2084 805332 char *opt_var = nullptr;
2085
2/2
✓ Branch 0 taken 1227 times.
✓ Branch 1 taken 804105 times.
805332 if (arg) {
2086 char *buff =
2087 1227 (char *)my_malloc(key_memory_mysql_options, FN_REFLEN + 1, MYF(MY_WME));
2088 1227 unpack_filename(buff, arg);
2089 1227 opt_var = my_strdup(key_memory_mysql_options, buff, MYF(MY_WME));
2090 1227 my_free(buff);
2091 }
2092 805332 return opt_var;
2093 }
2094
2095 void mysql_read_default_options(struct st_mysql_options *options,
2096 const char *filename, const char *group) {
2097 int argc;
2098 char *argv_buff[1], **argv;
2099 const char *groups[3];
2100 DBUG_TRACE;
2101 DBUG_PRINT("enter",
2102 ("file: %s group: %s", filename, group ? group : "NULL"));
2103
2104 static_assert(OPT_keep_this_one_last == array_elements(default_options),
2105 "OPT_keep_this_one_last needs to be the last element.");
2106
2107 argc = 1;
2108 argv = argv_buff;
2109 argv_buff[0] = const_cast<char *>("client");
2110 groups[0] = "client";
2111 groups[1] = group;
2112 groups[2] = nullptr;
2113
2114 MEM_ROOT alloc{PSI_NOT_INSTRUMENTED, 512};
2115 my_load_defaults(filename, groups, &argc, &argv, &alloc, nullptr);
2116 if (argc != 1) /* If some default option */
2117 {
2118 char **option = argv;
2119 while (*++option) {
2120 if (my_getopt_is_args_separator(option[0])) /* skip arguments separator */
2121 continue;
2122 /* DBUG_PRINT("info",("option: %s",option[0])); */
2123 if (option[0][0] == '-' && option[0][1] == '-') {
2124 char *end = strchr(*option, '=');
2125 char *opt_arg = nullptr;
2126 if (end != nullptr) {
2127 opt_arg = end + 1;
2128 *end = 0; /* Remove '=' */
2129 }
2130 /* Change all '_' in variable name to '-' */
2131 for (end = *option; end != nullptr; end = strchr(end, '_')) *end = '-';
2132 switch (find_type(*option + 2, &option_types, FIND_TYPE_BASIC)) {
2133 case OPT_port:
2134 if (opt_arg) options->port = atoi(opt_arg);
2135 break;
2136 case OPT_socket:
2137 if (opt_arg) {
2138 my_free(options->unix_socket);
2139 options->unix_socket =
2140 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2141 }
2142 break;
2143 case OPT_compress:
2144 options->compress = true;
2145 options->client_flag |= CLIENT_COMPRESS;
2146 break;
2147 case OPT_password:
2148 if (opt_arg) {
2149 my_free(options->password);
2150 options->password =
2151 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2152 }
2153 break;
2154 case OPT_pipe:
2155 options->protocol = MYSQL_PROTOCOL_PIPE;
2156 break;
2157 case OPT_connect_timeout:
2158 case OPT_timeout:
2159 if (opt_arg) options->connect_timeout = atoi(opt_arg);
2160 break;
2161 case OPT_user:
2162 if (opt_arg) {
2163 my_free(options->user);
2164 options->user =
2165 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2166 }
2167 break;
2168 case OPT_init_command:
2169 add_init_command(options, opt_arg);
2170 break;
2171 case OPT_host:
2172 if (opt_arg) {
2173 my_free(options->host);
2174 options->host =
2175 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2176 }
2177 break;
2178 case OPT_database:
2179 if (opt_arg) {
2180 my_free(options->db);
2181 options->db =
2182 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2183 }
2184 break;
2185 case OPT_debug:
2186 #ifndef MYSQL_SERVER
2187 mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace");
2188 break;
2189 #endif
2190 case OPT_return_found_rows:
2191 options->client_flag |= CLIENT_FOUND_ROWS;
2192 break;
2193 case OPT_ssl_key:
2194 my_free(options->ssl_key);
2195 options->ssl_key =
2196 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2197 break;
2198 case OPT_ssl_cert:
2199 my_free(options->ssl_cert);
2200 options->ssl_cert =
2201 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2202 break;
2203 case OPT_ssl_ca:
2204 my_free(options->ssl_ca);
2205 options->ssl_ca =
2206 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2207 break;
2208 case OPT_ssl_capath:
2209 my_free(options->ssl_capath);
2210 options->ssl_capath =
2211 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2212 break;
2213 case OPT_ssl_cipher:
2214 my_free(options->ssl_cipher);
2215 options->ssl_cipher =
2216 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2217 break;
2218 case OPT_tls_ciphersuites:
2219 EXTENSION_SET_STRING(options, tls_ciphersuites, opt_arg);
2220 break;
2221 case OPT_tls_version:
2222 EXTENSION_SET_SSL_STRING(options, tls_version, opt_arg,
2223 SSL_MODE_PREFERRED);
2224 break;
2225 case OPT_ssl_crl:
2226 EXTENSION_SET_SSL_STRING(options, ssl_crl, opt_arg,
2227 SSL_MODE_PREFERRED);
2228 break;
2229 case OPT_ssl_crlpath:
2230 EXTENSION_SET_SSL_STRING(options, ssl_crlpath, opt_arg,
2231 SSL_MODE_PREFERRED);
2232 break;
2233 case OPT_character_sets_dir:
2234 my_free(options->charset_dir);
2235 options->charset_dir =
2236 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2237 break;
2238 case OPT_default_character_set:
2239 my_free(options->charset_name);
2240 options->charset_name =
2241 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2242 break;
2243 case OPT_interactive_timeout:
2244 options->client_flag |= CLIENT_INTERACTIVE;
2245 break;
2246 case OPT_local_infile:
2247 if (!opt_arg || atoi(opt_arg) != 0)
2248 options->client_flag |= CLIENT_LOCAL_FILES;
2249 else
2250 options->client_flag &= ~CLIENT_LOCAL_FILES;
2251 break;
2252 case OPT_disable_local_infile:
2253 options->client_flag &= ~CLIENT_LOCAL_FILES;
2254 break;
2255 case OPT_max_allowed_packet:
2256 if (opt_arg) options->max_allowed_packet = atoi(opt_arg);
2257 break;
2258 case OPT_protocol:
2259 if ((options->protocol = find_type(opt_arg, &sql_protocol_typelib,
2260 FIND_TYPE_BASIC)) <= 0) {
2261 my_message_local(ERROR_LEVEL, EE_UNKNOWN_PROTOCOL_OPTION,
2262 opt_arg);
2263 exit(1);
2264 }
2265 break;
2266 case OPT_shared_memory_base_name:
2267 #if defined(_WIN32)
2268 my_free(options->shared_memory_base_name);
2269
2270 options->shared_memory_base_name =
2271 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2272 #endif
2273 break;
2274 case OPT_multi_results:
2275 options->client_flag |= CLIENT_MULTI_RESULTS;
2276 break;
2277 case OPT_multi_statements:
2278 case OPT_multi_queries:
2279 options->client_flag |=
2280 CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS;
2281 break;
2282 case OPT_report_data_truncation:
2283 options->report_data_truncation =
2284 opt_arg ? (atoi(opt_arg) != 0) : true;
2285 break;
2286 case OPT_plugin_dir: {
2287 char buff[FN_REFLEN], buff2[FN_REFLEN];
2288 if (strlen(opt_arg) >= FN_REFLEN) opt_arg[FN_REFLEN] = '\0';
2289 if (my_realpath(buff, opt_arg, 0)) {
2290 DBUG_PRINT("warning",
2291 ("failed to normalize the plugin path: %s", opt_arg));
2292 break;
2293 }
2294 convert_dirname(buff2, buff, nullptr);
2295 EXTENSION_SET_STRING(options, plugin_dir, buff2);
2296 } break;
2297 case OPT_default_auth:
2298 EXTENSION_SET_STRING(options, default_auth, opt_arg);
2299 break;
2300 case OPT_bind_address:
2301 my_free(options->bind_address);
2302 options->bind_address =
2303 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2304 break;
2305 case OPT_enable_cleartext_plugin:
2306 ENSURE_EXTENSIONS_PRESENT(options);
2307 options->extension->enable_cleartext_plugin =
2308 (!opt_arg || atoi(opt_arg) != 0) ? true : false;
2309 break;
2310 case OPT_optional_resultset_metadata:
2311 if (!opt_arg || atoi(opt_arg) != 0)
2312 options->client_flag |= CLIENT_OPTIONAL_RESULTSET_METADATA;
2313 else
2314 options->client_flag &= ~CLIENT_OPTIONAL_RESULTSET_METADATA;
2315 break;
2316
2317 default:
2318 DBUG_PRINT("warning", ("unknown option: %s", option[0]));
2319 }
2320 }
2321 }
2322 }
2323 }
2324
2325 /**************************************************************************
2326 Get column lengths of the current row
2327 If one uses mysql_use_result, res->lengths contains the length information,
2328 else the lengths are calculated from the offset between pointers.
2329 **************************************************************************/
2330
2331 86360057 static void cli_fetch_lengths(ulong *to, MYSQL_ROW column,
2332 unsigned int field_count) {
2333 ulong *prev_length;
2334 86360057 char *start = nullptr;
2335 MYSQL_ROW end;
2336
2337 86360057 prev_length = nullptr; /* Keep gcc happy */
2338
2/2
✓ Branch 0 taken 520739820 times.
✓ Branch 1 taken 86360057 times.
607099877 for (end = column + field_count + 1; column != end; column++, to++) {
2339
2/2
✓ Branch 0 taken 34461763 times.
✓ Branch 1 taken 486278057 times.
520739820 if (!*column) {
2340 34461763 *to = 0; /* Null */
2341 34461763 continue;
2342 }
2343
2/2
✓ Branch 0 taken 399918001 times.
✓ Branch 1 taken 86360056 times.
486278057 if (start) /* Found end of prev string */
2344 399918001 *prev_length = (ulong)(*column - start - 1);
2345 486278057 start = *column;
2346 486278057 prev_length = to;
2347 }
2348 86360057 }
2349
2350 /**
2351 Read field metadata from field descriptor and store it in MYSQL_FIELD
2352 structure. String values in MYSQL_FIELD are allocated in a given allocator
2353 root.
2354
2355 @param mysql connection handle
2356 @param alloc memory allocator root
2357 @param default_value flag telling if default values should be read from
2358 descriptor
2359 @param server_capabilities protocol capability flags which determine format
2360 of the descriptor
2361 @param row field descriptor
2362 @param field address of MYSQL_FIELD structure to store metadata in.
2363
2364 @returns 0 on success.
2365 */
2366
2367 26986416 static int unpack_field(MYSQL *mysql, MEM_ROOT *alloc, bool default_value,
2368 uint server_capabilities, MYSQL_ROWS *row,
2369 MYSQL_FIELD *field) {
2370 ulong lengths[9]; /* Max length of each field */
2371
1/2
✓ Branch 0 taken 26986415 times.
✗ Branch 1 not taken.
26986416 DBUG_TRACE;
2372
2373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26986415 times.
26986415 if (!field) {
2374 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
2375 return 1;
2376 }
2377
2378 26986415 memset(field, 0, sizeof(MYSQL_FIELD));
2379
2380
1/2
✓ Branch 0 taken 26986415 times.
✗ Branch 1 not taken.
26986415 if (server_capabilities & CLIENT_PROTOCOL_41) {
2381 uchar *pos;
2382 /* fields count may be wrong */
2383
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 26986373 times.
26986415 cli_fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7);
2384
1/2
✓ Branch 0 taken 26986411 times.
✗ Branch 1 not taken.
26986413 field->catalog = strmake_root(alloc, (char *)row->data[0], lengths[0]);
2385
1/2
✓ Branch 0 taken 26986412 times.
✗ Branch 1 not taken.
26986411 field->db = strmake_root(alloc, (char *)row->data[1], lengths[1]);
2386
1/2
✓ Branch 0 taken 26986415 times.
✗ Branch 1 not taken.
26986412 field->table = strmake_root(alloc, (char *)row->data[2], lengths[2]);
2387
1/2
✓ Branch 0 taken 26986414 times.
✗ Branch 1 not taken.
26986415 field->org_table = strmake_root(alloc, (char *)row->data[3], lengths[3]);
2388
1/2
✓ Branch 0 taken 26986416 times.
✗ Branch 1 not taken.
26986414 field->name = strmake_root(alloc, (char *)row->data[4], lengths[4]);
2389
1/2
✓ Branch 0 taken 26986414 times.
✗ Branch 1 not taken.
26986416 field->org_name = strmake_root(alloc, (char *)row->data[5], lengths[5]);
2390
2391 26986414 field->catalog_length = lengths[0];
2392 26986414 field->db_length = lengths[1];
2393 26986414 field->table_length = lengths[2];
2394 26986414 field->org_table_length = lengths[3];
2395 26986414 field->name_length = lengths[4];
2396 26986414 field->org_name_length = lengths[5];
2397
2398 /* Unpack fixed length parts */
2399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26986414 times.
26986414 if (lengths[6] != 12) {
2400 /* malformed packet. signal an error. */
2401 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2402 return 1;
2403 }
2404
2405 26986414 pos = (uchar *)row->data[6];
2406 26986414 field->charsetnr = uint2korr(pos);
2407 26986413 field->length = (uint)uint4korr(pos + 2);
2408 26986412 field->type = (enum enum_field_types)pos[6];
2409 26986412 field->flags = uint2korr(pos + 7);
2410 26986412 field->decimals = (uint)pos[9];
2411
2412
8/8
✓ Branch 0 taken 7041277 times.
✓ Branch 1 taken 19945135 times.
✓ Branch 2 taken 77786 times.
✓ Branch 3 taken 6963491 times.
✓ Branch 4 taken 20019032 times.
✓ Branch 5 taken 3889 times.
✓ Branch 6 taken 49694 times.
✓ Branch 7 taken 19969338 times.
26986412 if (IS_NUM(field->type)) field->flags |= NUM_FLAG;
2413
4/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 26986370 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 22 times.
26986412 if (default_value && row->data[7]) {
2414
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 field->def = strmake_root(alloc, (char *)row->data[7], lengths[7]);
2415 20 field->def_length = lengths[7];
2416 } else
2417 26986392 field->def = nullptr;
2418 26986412 field->max_length = 0;
2419 }
2420 #ifndef DELETE_SUPPORT_OF_4_0_PROTOCOL
2421 else {
2422 /*
2423 If any of the row->data[] below is NULL, it can result in a
2424 crash. Error out early as it indicates a malformed packet.
2425 For data[0], data[1] and data[5], strmake_root() will handle
2426 NULL values.
2427 */
2428 if (!row->data[2] || !row->data[3] || !row->data[4]) {
2429 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2430 return 1;
2431 }
2432
2433 cli_fetch_lengths(&lengths[0], row->data, default_value ? 6 : 5);
2434 field->org_table = field->table =
2435 strmake_root(alloc, (char *)row->data[0], lengths[0]);
2436 field->name = strmake_root(alloc, (char *)row->data[1], lengths[1]);
2437 field->length = (uint)uint3korr((uchar *)row->data[2]);
2438 field->type = (enum enum_field_types)(uchar)row->data[3][0];
2439
2440 field->catalog = const_cast<char *>("");
2441 field->db = const_cast<char *>("");
2442 field->catalog_length = 0;
2443 field->db_length = 0;
2444 field->org_table_length = field->table_length = lengths[0];
2445 field->name_length = lengths[1];
2446
2447 if (server_capabilities & CLIENT_LONG_FLAG) {
2448 if (lengths[4] != 3) {
2449 /* malformed packet. signal an error. */
2450 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2451 return 1;
2452 }
2453 field->flags = uint2korr((uchar *)row->data[4]);
2454 field->decimals = (uint)(uchar)row->data[4][2];
2455 } else {
2456 if (lengths[4] != 2) {
2457 /* malformed packet. signal an error. */
2458 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2459 return 1;
2460 }
2461 field->flags = (uint)(uchar)row->data[4][0];
2462 field->decimals = (uint)(uchar)row->data[4][1];
2463 }
2464 if (IS_NUM(field->type)) field->flags |= NUM_FLAG;
2465 if (default_value && row->data[5]) {
2466 field->def = strmake_root(alloc, (char *)row->data[5], lengths[5]);
2467 field->def_length = lengths[5];
2468 } else
2469 field->def = nullptr;
2470 field->max_length = 0;
2471 }
2472 #endif /* DELETE_SUPPORT_OF_4_0_PROTOCOL */
2473 26986412 return 0;
2474 26986412 }
2475
2476 /***************************************************************************
2477 Change field rows to field structs
2478 ***************************************************************************/
2479
2480 20 MYSQL_FIELD *unpack_fields(MYSQL *mysql, MYSQL_ROWS *data, MEM_ROOT *alloc,
2481 uint fields, bool default_value,
2482 uint server_capabilities) {
2483 MYSQL_ROWS *row;
2484 MYSQL_FIELD *field, *result;
2485
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 DBUG_TRACE;
2486
2487
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 field = result = (MYSQL_FIELD *)alloc->Alloc((uint)sizeof(*field) * fields);
2488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (!result) {
2489 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2490 return nullptr;
2491 }
2492 20 memset(field, 0, sizeof(MYSQL_FIELD) * fields);
2493
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 20 times.
62 for (row = data; row; row = row->next, field++) {
2494 /* fields count may be wrong */
2495
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
42 if (field < result || static_cast<uint>(field - result) >= fields) {
2496 return nullptr;
2497 }
2498
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
42 if (unpack_field(mysql, alloc, default_value, server_capabilities, row,
2499 field)) {
2500 return nullptr;
2501 }
2502 }
2503 20 return result;
2504 20 }
2505
2506 /**
2507 Read metadata resultset from server in asynchronous way.
2508
2509 @param[in] mysql connection handle
2510 @param[in] alloc memory allocator root
2511 @param[in] field_count total number of fields
2512 @param[in] field number of columns in single field descriptor
2513 @param[out] ret an array of field rows
2514
2515 @retval NET_ASYNC_NOT_READY metadata resultset not read completely
2516 @retval NET_ASYNC_COMPLETE finished reading metadata resultset
2517 */
2518 122 net_async_status cli_read_metadata_ex_nonblocking(MYSQL *mysql, MEM_ROOT *alloc,
2519 ulong field_count,
2520 unsigned int field,
2521 MYSQL_FIELD **ret) {
2522
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 DBUG_TRACE;
2523 uchar *pos;
2524 ulong pkt_len;
2525 122 NET *net = &mysql->net;
2526
2/6
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 122 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
122 MYSQL_ASYNC *async_data = ASYNC_DATA(mysql);
2527 122 *ret = nullptr;
2528
2529
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (!async_data->async_read_metadata_field_len) {
2530 122 async_data->async_read_metadata_field_len =
2531
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 (ulong *)alloc->Alloc(sizeof(ulong) * field);
2532 }
2533
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (!async_data->async_read_metadata_fields) {
2534 122 async_data->async_read_metadata_fields =
2535
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 (MYSQL_FIELD *)alloc->Alloc((uint)sizeof(MYSQL_FIELD) * field_count);
2536
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (async_data->async_read_metadata_fields)
2537 122 memset(async_data->async_read_metadata_fields, 0,
2538 sizeof(MYSQL_FIELD) * field_count);
2539 }
2540
2541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (!async_data->async_read_metadata_fields) {
2542 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2543 goto end;
2544 }
2545
2546
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (!async_data->async_read_metadata_data.data) {
2547 122 async_data->async_read_metadata_data.data =
2548
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 (MYSQL_ROW)alloc->Alloc(sizeof(char *) * (field + 1));
2549 122 memset(async_data->async_read_metadata_data.data, 0,
2550 122 sizeof(char *) * (field + 1));
2551 }
2552
2553 /*
2554 In this below loop we read each column info as 1 single row
2555 and save it in mysql->fields array
2556 */
2557
2/2
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 122 times.
257 while (async_data->async_read_metadata_cur_field < field_count) {
2558 int res;
2559
1/2
✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
135 if (read_one_row_nonblocking(mysql, field,
2560 async_data->async_read_metadata_data.data,
2561 async_data->async_read_metadata_field_len,
2562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 &res) == NET_ASYNC_NOT_READY) {
2563 return NET_ASYNC_NOT_READY;
2564 }
2565
2566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 if (res == -1) {
2567 goto end;
2568 }
2569
2570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 if (unpack_field(mysql, alloc, false, mysql->server_capabilities,
2571 &async_data->async_read_metadata_data,
2572 135 async_data->async_read_metadata_fields +
2573
1/2
✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
135 async_data->async_read_metadata_cur_field)) {
2574 goto end;
2575 }
2576 135 async_data->async_read_metadata_cur_field++;
2577 }
2578
2579 /* Read EOF packet in case of old client */
2580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (!(mysql->server_capabilities & CLIENT_DEPRECATE_EOF)) {
2581 if (cli_safe_read_nonblocking(mysql, nullptr, &pkt_len) ==
2582 NET_ASYNC_NOT_READY) {
2583 return NET_ASYNC_NOT_READY;
2584 }
2585
2586 if (pkt_len == packet_error) {
2587 goto end;
2588 }
2589
2590 pos = net->read_pos;
2591 if (*pos == 254) {
2592 mysql->warning_count = uint2korr(pos + 1);
2593 mysql->server_status = uint2korr(pos + 3);
2594 }
2595 }
2596 122 *ret = async_data->async_read_metadata_fields;
2597
2598 122 end:
2599 122 async_data->async_read_metadata_field_len = nullptr;
2600 122 async_data->async_read_metadata_fields = nullptr;
2601 122 memset(&async_data->async_read_metadata_data, 0,
2602 sizeof(async_data->async_read_metadata_data));
2603 122 async_data->async_read_metadata_cur_field = 0;
2604 122 return NET_ASYNC_COMPLETE;
2605 122 }
2606
2607 /**
2608 Read metadata resultset from server
2609 Memory allocated in a given allocator root.
2610
2611 @param[in] mysql connection handle
2612 @param[in] alloc memory allocator root
2613 @param[in] field_count total number of fields
2614 @param[in] field number of columns in single field descriptor
2615
2616 @retval an array of field rows
2617
2618 */
2619 9042474 MYSQL_FIELD *cli_read_metadata_ex(MYSQL *mysql, MEM_ROOT *alloc,
2620 ulong field_count, unsigned int field) {
2621 ulong *len;
2622 uint f;
2623 uchar *pos;
2624 MYSQL_FIELD *fields, *result;
2625 MYSQL_ROWS data;
2626 9042474 NET *net = &mysql->net;
2627 size_t size;
2628
2629
1/2
✓ Branch 0 taken 9042478 times.
✗ Branch 1 not taken.
9042474 DBUG_TRACE;
2630
2631
1/2
✓ Branch 0 taken 9042477 times.
✗ Branch 1 not taken.
9042478 len = (ulong *)alloc->Alloc(sizeof(ulong) * field);
2632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9042477 times.
9042477 if (!len) {
2633 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2634 end_server(mysql);
2635 return nullptr;
2636 }
2637 9042477 size = sizeof(MYSQL_FIELD) * field_count;
2638
2639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9042477 times.
9042477 if (field_count != (size / sizeof(MYSQL_FIELD))) {
2640 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2641 end_server(mysql);
2642 return nullptr;
2643 }
2644
2645
1/2
✓ Branch 0 taken 9042477 times.
✗ Branch 1 not taken.
9042477 fields = result = (MYSQL_FIELD *)alloc->Alloc(size);
2646
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9042477 times.
9042477 if (!result) {
2647 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2648 end_server(mysql);
2649 return nullptr;
2650 }
2651 9042477 memset(fields, 0, sizeof(MYSQL_FIELD) * field_count);
2652
2653
1/2
✓ Branch 0 taken 9042477 times.
✗ Branch 1 not taken.
9042477 data.data = (MYSQL_ROW)alloc->Alloc(sizeof(char *) * (field + 1));
2654 9042477 memset(data.data, 0, sizeof(char *) * (field + 1));
2655
2656 /*
2657 In this below loop we read each column info as 1 single row
2658 and save it in mysql->fields array
2659 */
2660
2/2
✓ Branch 0 taken 26986236 times.
✓ Branch 1 taken 9042479 times.
36028715 for (f = 0; f < field_count; ++f) {
2661
2/4
✓ Branch 0 taken 26986239 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 26986239 times.
26986236 if (read_one_row(mysql, field, data.data, len) == -1) return nullptr;
2662
2/4
✓ Branch 0 taken 26986238 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 26986238 times.
26986239 if (unpack_field(mysql, alloc, false, mysql->server_capabilities, &data,
2663 fields++))
2664 return nullptr;
2665 }
2666 /* Read EOF packet in case of old client */
2667
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9042479 times.
9042479 if (!(mysql->server_capabilities & CLIENT_DEPRECATE_EOF)) {
2668 if (packet_error == cli_safe_read(mysql, nullptr)) return nullptr;
2669 pos = net->read_pos;
2670 if (*pos == 254) {
2671 mysql->warning_count = uint2korr(pos + 1);
2672 mysql->server_status = uint2korr(pos + 3);
2673 }
2674 }
2675 9042478 return result;
2676 9042478 }
2677
2678 9040934 static int alloc_field_alloc(MYSQL *mysql) {
2679
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 9040927 times.
9040934 if (mysql->field_alloc == nullptr) {
2680 10 mysql->field_alloc =
2681 7 new (my_malloc(key_memory_MYSQL, sizeof(MEM_ROOT), MYF(MY_WME)))
2682 7 MEM_ROOT(PSI_NOT_INSTRUMENTED, 8192); /* Assume rowlength < 8192 */
2683
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (mysql->field_alloc == nullptr) {
2684 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2685 return 1;
2686 }
2687 }
2688 /* At this point the NET is receiving a resultset. max packet should be set */
2689
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9040937 times.
9040937 assert(mysql->net.max_packet_size != 0);
2690 /* Limit the size of the columns buffer to MAX packet size or 1M */
2691 9040936 mysql->field_alloc->set_max_capacity(
2692 9040937 std::max(1024UL * 1024UL, mysql->net.max_packet_size));
2693 9040932 return 0;
2694 }
2695
2696 /**
2697 Read metadata resultset from server
2698
2699 @param[in] mysql connection handle
2700 @param[in] field_count total number of fields
2701 @param[in] field number of columns in single field descriptor
2702
2703 @retval an array of field rows
2704
2705 */
2706 9040811 MYSQL_FIELD *cli_read_metadata(MYSQL *mysql, ulong field_count,
2707 unsigned int field) {
2708 9040811 alloc_field_alloc(mysql);
2709 9040811 return cli_read_metadata_ex(mysql, mysql->field_alloc, field_count, field);
2710 }
2711
2712 /**
2713 Helper method to read metadata in asynchronous way.
2714 */
2715 122 static net_async_status cli_read_metadata_nonblocking(MYSQL *mysql,
2716 ulong field_count,
2717 unsigned int field,
2718 MYSQL_FIELD **ret) {
2719 122 alloc_field_alloc(mysql);
2720 122 if (cli_read_metadata_ex_nonblocking(mysql, mysql->field_alloc, field_count,
2721
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 field, ret) == NET_ASYNC_NOT_READY) {
2722 return NET_ASYNC_NOT_READY;
2723 }
2724 122 return NET_ASYNC_COMPLETE;
2725 }
2726
2727 /**
2728 Read resultset metadata returned by COM_QUERY command.
2729
2730 @param[in] mysql Client connection handle.
2731 @param[in] pos Position in the packet where the metadata
2732 starts.
2733 @param[in] field_count Number of columns in the field descriptor.
2734
2735 @retval 0 Success.
2736 @retval 1 Error.
2737 */
2738 9038557 static int read_com_query_metadata(MYSQL *mysql, uchar *pos,
2739 ulong field_count) {
2740 /* Store resultset metadata flag. */
2741
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 9038526 times.
9038557 if (mysql->client_flag & CLIENT_OPTIONAL_RESULTSET_METADATA) {
2742 31 mysql->resultset_metadata = static_cast<enum enum_resultset_metadata>(*pos);
2743 } else {
2744 9038526 mysql->resultset_metadata = RESULTSET_METADATA_FULL;
2745 }
2746
2747
2/3
✓ Branch 0 taken 9038542 times.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
9038557 switch (mysql->resultset_metadata) {
2748 9038542 case RESULTSET_METADATA_FULL:
2749 /* Read metadata. */
2750
2/6
✓ Branch 0 taken 9001157 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9001157 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
9001157 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_FIELD_DEF);
2751
2752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9038548 times.
9038542 if (!(mysql->fields = cli_read_metadata(mysql, field_count,
2753
1/2
✓ Branch 0 taken 9038542 times.
✗ Branch 1 not taken.
9038542 protocol_41(mysql) ? 7 : 5))) {
2754 mysql->field_alloc->Clear();
2755 return 1;
2756 }
2757 9038548 break;
2758
2759 16 case RESULTSET_METADATA_NONE:
2760 /* Skip metadata. */
2761 16 mysql->fields = nullptr;
2762 16 break;
2763
2764 default:
2765 /* Unknown metadata flag. */
2766 mysql->fields = nullptr;
2767 return 1;
2768 }
2769
2770 9038564 return 0;
2771 }
2772
2773 /**
2774 Read resultset metadata returned by COM_QUERY command in asynchronous way.
2775
2776 @param[in] mysql Client connection handle.
2777 @param[in] pos Position in the packet where the metadata
2778 starts.
2779 @param[in] field_count Number of columns in the field descriptor.
2780 @param[out] res set to false in case of success and true for
2781 error.
2782
2783 @retval NET_ASYNC_NOT_READY metadata resultset not read completely
2784 @retval NET_ASYNC_COMPLETE finished reading metadata resultset
2785 */
2786 122 static net_async_status read_com_query_metadata_nonblocking(MYSQL *mysql,
2787 uchar *pos,
2788 ulong field_count,
2789 int *res) {
2790
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 DBUG_TRACE;
2791 /* pos is only set on the first reentrant call. */
2792
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (pos) {
2793 /* Store resultset metadata flag. */
2794
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (mysql->client_flag & CLIENT_OPTIONAL_RESULTSET_METADATA) {
2795 mysql->resultset_metadata =
2796 static_cast<enum enum_resultset_metadata>(*pos);
2797 } else {
2798 122 mysql->resultset_metadata = RESULTSET_METADATA_FULL;
2799 }
2800 }
2801
2802
1/3
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
122 switch (mysql->resultset_metadata) {
2803 122 case RESULTSET_METADATA_FULL:
2804 /* Read metadata. */
2805
2/10
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 122 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
122 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_FIELD_DEF);
2806
2807
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (cli_read_metadata_nonblocking(
2808
2/4
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 122 times.
244 mysql, field_count, protocol_41(mysql) ? 7 : 5, &mysql->fields) ==
2809 NET_ASYNC_NOT_READY) {
2810 return NET_ASYNC_NOT_READY;
2811 }
2812
2813
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (!mysql->fields) {
2814 mysql->field_alloc->Clear();
2815 *res = 1;
2816 return NET_ASYNC_COMPLETE;
2817 }
2818 122 break;
2819
2820 case RESULTSET_METADATA_NONE:
2821 /* Skip metadata. */
2822 mysql->fields = nullptr;
2823 break;
2824
2825 default:
2826 /* Unknown metadata flag. */
2827 mysql->fields = nullptr;
2828 *res = 1;
2829 return NET_ASYNC_COMPLETE;
2830 }
2831
2832 122 *res = 0;
2833 122 return NET_ASYNC_COMPLETE;
2834 122 }
2835
2836 167275 net_async_status cli_read_rows_nonblocking(MYSQL *mysql,
2837 MYSQL_FIELD *mysql_fields,
2838 unsigned int fields,
2839 MYSQL_DATA **result_out) {
2840 uint field;
2841 ulong pkt_len;
2842 ulong len;
2843 uchar *cp;
2844 char *to, *end_to;
2845 MYSQL_ROWS *cur;
2846 167275 NET *net = &mysql->net;
2847 bool is_data_packet;
2848
1/2
✓ Branch 0 taken 167275 times.
✗ Branch 1 not taken.
167275 DBUG_TRACE;
2849
2/6
✓ Branch 0 taken 167275 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 167275 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
167275 MYSQL_ASYNC *async_context = ASYNC_DATA(mysql);
2850
1/2
✓ Branch 0 taken 167275 times.
✗ Branch 1 not taken.
167275 NET_ASYNC *net_async = NET_ASYNC_DATA(net);
2851 167275 *result_out = nullptr;
2852
2853
3/4
✓ Branch 0 taken 167275 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 167144 times.
✓ Branch 3 taken 131 times.
167275 if (cli_safe_read_nonblocking(mysql, &is_data_packet, &pkt_len) ==
2854 NET_ASYNC_NOT_READY) {
2855 167144 return NET_ASYNC_NOT_READY;
2856 }
2857
2858 131 mysql->packet_length = pkt_len;
2859
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (pkt_len == packet_error) {
2860 if (net_async->read_rows_is_first_read) {
2861 free_rows(async_context->rows_result_buffer);
2862 async_context->rows_result_buffer = nullptr;
2863 }
2864 net_async->read_rows_is_first_read = true;
2865 return NET_ASYNC_COMPLETE;
2866 }
2867
2868
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 if (net_async->read_rows_is_first_read) {
2869 MYSQL_DATA *result;
2870 131 if (!(result =
2871
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 (MYSQL_DATA *)my_malloc(key_memory_MYSQL_DATA, sizeof(MYSQL_DATA),
2872
2/4
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 131 times.
262 MYF(MY_WME | MY_ZEROFILL))) ||
2873 131 !(result->alloc =
2874
2/4
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 131 times.
131 (MEM_ROOT *)my_malloc(key_memory_MYSQL_DATA, sizeof(MEM_ROOT),
2875 MYF(MY_WME | MY_ZEROFILL)))) {
2876 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2877 net_async->read_rows_is_first_read = true;
2878 free_rows(result);
2879 return NET_ASYNC_COMPLETE;
2880 }
2881 131 async_context->rows_result_buffer = result;
2882 131 ::new ((void *)result->alloc)
2883 131 MEM_ROOT(PSI_NOT_INSTRUMENTED, 8192); /* Assume rowlength < 8192 */
2884 131 async_context->prev_row_ptr = &result->data;
2885 131 result->rows = 0;
2886 131 result->fields = fields;
2887
2888 131 net_async->read_rows_is_first_read = false;
2889 }
2890
2891 /*
2892 The last EOF packet is either a single 254 character or (in MySQL 4.1)
2893 254 followed by 1-7 status bytes or an OK packet starting with 0xFE
2894 */
2895
5/6
✓ Branch 0 taken 270 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 139 times.
✓ Branch 3 taken 131 times.
✓ Branch 4 taken 139 times.
✓ Branch 5 taken 131 times.
270 while (*(cp = net->read_pos) == 0 || is_data_packet) {
2896 139 MYSQL_DATA *result = async_context->rows_result_buffer;
2897 139 result->rows++;
2898
3/6
✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 139 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 139 times.
278 if (!(cur = (MYSQL_ROWS *)result->alloc->Alloc(sizeof(MYSQL_ROWS))) ||
2899
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
139 !(cur->data = ((MYSQL_ROW)result->alloc->Alloc(
2900
1/2
✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
139 (fields + 1) * sizeof(char *) + pkt_len)))) {
2901 free_rows(result);
2902 async_context->rows_result_buffer = nullptr;
2903 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2904 net_async->read_rows_is_first_read = true;
2905 return NET_ASYNC_COMPLETE;
2906 }
2907 139 *async_context->prev_row_ptr = cur;
2908 139 async_context->prev_row_ptr = &cur->next;
2909 139 to = (char *)(cur->data + fields + 1);
2910 139 end_to = to + pkt_len - 1;
2911
2/2
✓ Branch 0 taken 166 times.
✓ Branch 1 taken 139 times.
305 for (field = 0; field < fields; field++) {
2912
3/4
✓ Branch 0 taken 166 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 157 times.
166 if ((len = (ulong)net_field_length(&cp)) ==
2913 NULL_LENGTH) { /* null field */
2914 9 cur->data[field] = nullptr;
2915 } else {
2916 157 cur->data[field] = to;
2917
2/4
✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 157 times.
157 if (to > end_to || len > (ulong)(end_to - to)) {
2918 free_rows(result);
2919 async_context->rows_result_buffer = nullptr;
2920 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2921 net_async->read_rows_is_first_read = true;
2922 return NET_ASYNC_COMPLETE;
2923 }
2924 157 memcpy(to, (char *)cp, len);
2925 157 to[len] = 0;
2926 157 to += len + 1;
2927 157 cp += len;
2928
1/2
✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
157 if (mysql_fields) {
2929
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 11 times.
157 if (mysql_fields[field].max_length < len)
2930 146 mysql_fields[field].max_length = len;
2931 }
2932 }
2933 }
2934 139 cur->data[field] = to; /* End of last field */
2935
2/4
✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 139 times.
139 if (cli_safe_read_nonblocking(mysql, &is_data_packet, &pkt_len) ==
2936 NET_ASYNC_NOT_READY) {
2937 return NET_ASYNC_NOT_READY;
2938 }
2939 139 mysql->packet_length = pkt_len;
2940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
139 if (pkt_len == packet_error) {
2941 free_rows(async_context->rows_result_buffer);
2942 async_context->rows_result_buffer = nullptr;
2943 net_async->read_rows_is_first_read = true;
2944 return NET_ASYNC_COMPLETE;
2945 }
2946 }
2947
2948 131 *async_context->prev_row_ptr = nullptr; /* last pointer is null */
2949 /* read EOF packet or OK packet if it is new client */
2950
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 if (pkt_len > 1) {
2951
2/4
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
✗ Branch 3 not taken.
131 if (mysql->server_capabilities & CLIENT_DEPRECATE_EOF && !is_data_packet)
2952
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 read_ok_ex(mysql, pkt_len);
2953 else {
2954 mysql->warning_count = uint2korr(cp + 1);
2955 mysql->server_status = uint2korr(cp + 3);
2956 }
2957
2958
3/8
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 131 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
131 DBUG_PRINT("info", ("status: %u warning_count: %u", mysql->server_status,
2959 mysql->warning_count));
2960 }
2961
2962 #if defined(CLIENT_PROTOCOL_TRACING)
2963
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 119 times.
131 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
2964
2/10
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
12 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
2965 else
2966
2/10
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 119 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
119 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
2967 #endif
2968
3/8
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 131 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
131 DBUG_PRINT("exit",
2969 ("Got %lu rows", (ulong)async_context->rows_result_buffer->rows));
2970 131 *result_out = async_context->rows_result_buffer;
2971 131 async_context->rows_result_buffer = nullptr;
2972 131 net_async->read_rows_is_first_read = true;
2973 131 return NET_ASYNC_COMPLETE;
2974 167275 }
2975
2976 /* Read all rows (data) from server */
2977
2978 8963003 MYSQL_DATA *cli_read_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields,
2979 unsigned int fields) {
2980 uint field;
2981 ulong pkt_len;
2982 ulong len;
2983 uchar *cp;
2984 char *to, *end_to;
2985 MYSQL_DATA *result;
2986 MYSQL_ROWS **prev_ptr, *cur;
2987 8963003 NET *net = &mysql->net;
2988 bool is_data_packet;
2989
1/2
✓ Branch 0 taken 8963004 times.
✗ Branch 1 not taken.
8963003 DBUG_TRACE;
2990
2991
3/4
✓ Branch 0 taken 8963003 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4015 times.
✓ Branch 3 taken 8958988 times.
8963004 if ((pkt_len = cli_safe_read(mysql, &is_data_packet)) == packet_error)
2992 4015 return nullptr;
2993
2994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8958988 times.
8958988 if (pkt_len == 0) return nullptr;
2995 8958989 if (!(result =
2996
1/2
✓ Branch 0 taken 8958989 times.
✗ Branch 1 not taken.
8958988 (MYSQL_DATA *)my_malloc(key_memory_MYSQL_DATA, sizeof(MYSQL_DATA),
2997
2/4
✓ Branch 0 taken 8958989 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8958989 times.
17917978 MYF(MY_WME | MY_ZEROFILL))) ||
2998 8958989 !(result->alloc =
2999
2/4
✓ Branch 0 taken 8958989 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8958989 times.
8958989 (MEM_ROOT *)my_malloc(key_memory_MYSQL_DATA, sizeof(MEM_ROOT),
3000 MYF(MY_WME | MY_ZEROFILL)))) {
3001 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3002 free_rows(result);
3003 return nullptr;
3004 }
3005 8958989 ::new ((void *)result->alloc)
3006 8958989 MEM_ROOT(PSI_NOT_INSTRUMENTED, 8192); /* Assume rowlength < 8192 */
3007 8958990 prev_ptr = &result->data;
3008 8958990 result->rows = 0;
3009 8958990 result->fields = fields;
3010
3011 /*
3012 The last EOF packet is either a single 254 character or (in MySQL 4.1)
3013 254 followed by 1-7 status bytes or an OK packet starting with 0xFE
3014 */
3015
3016
6/6
✓ Branch 0 taken 104987379 times.
✓ Branch 1 taken 1221955 times.
✓ Branch 2 taken 96028497 times.
✓ Branch 3 taken 8958882 times.
✓ Branch 4 taken 97250452 times.
✓ Branch 5 taken 8958882 times.
106209334 while (*(cp = net->read_pos) == 0 || is_data_packet) {
3017 97250452 ulong packet_left = pkt_len;
3018 97250452 result->rows++;
3019
3/6
✓ Branch 0 taken 97250440 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 97250440 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 97250438 times.
194500890 if (!(cur = (MYSQL_ROWS *)result->alloc->Alloc(sizeof(MYSQL_ROWS))) ||
3020
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 97250437 times.
97250438 !(cur->data = ((MYSQL_ROW)result->alloc->Alloc(
3021
1/2
✓ Branch 0 taken 97250438 times.
✗ Branch 1 not taken.
97250440 (fields + 1) * sizeof(char *) + pkt_len)))) {
3022 free_rows(result);
3023 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3024 return nullptr;
3025 }
3026 97250438 *prev_ptr = cur;
3027 97250438 prev_ptr = &cur->next;
3028 97250438 to = (char *)(cur->data + fields + 1);
3029 97250438 end_to = to + pkt_len - 1;
3030
2/2
✓ Branch 0 taken 418515610 times.
✓ Branch 1 taken 97250445 times.
515766055 for (field = 0; field < fields; field++) {
3031 418515610 uint length_len = 0;
3032
3/4
✓ Branch 0 taken 418515602 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 418515608 times.
837031210 if (packet_left < 1 ||
3033
2/4
✓ Branch 0 taken 418515600 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 418515608 times.
418515602 packet_left < (length_len = net_field_length_size(cp))) {
3034 free_rows(result);
3035 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
3036 return nullptr;
3037 }
3038
3/4
✓ Branch 0 taken 418515617 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46791792 times.
✓ Branch 3 taken 371723825 times.
418515608 if ((len = (ulong)net_field_length(&cp)) ==
3039 NULL_LENGTH) { /* null field */
3040 46791792 cur->data[field] = nullptr;
3041 46791792 packet_left -= length_len;
3042 } else {
3043 371723825 cur->data[field] = to;
3044
2/4
✓ Branch 0 taken 371723823 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 371723823 times.
371723825 DBUG_EXECUTE_IF("simulate_invalid_packet_data", {
3045 to = end_to + 1;
3046 len = ULONG_MAX - 1;
3047 });
3048
2/4
✓ Branch 0 taken 371723825 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 371723825 times.
371723823 if (to > end_to || len > (ulong)(end_to - to)) {
3049 free_rows(result);
3050 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
3051 return nullptr;
3052 }
3053 371723825 memcpy(to, (char *)cp, len);
3054 371723825 to[len] = 0;
3055 371723825 to += len + 1;
3056 371723825 cp += len;
3057 371723825 packet_left -= len + length_len;
3058
2/2
✓ Branch 0 taken 371723461 times.
✓ Branch 1 taken 364 times.
371723825 if (mysql_fields) {
3059
2/2
✓ Branch 0 taken 18392525 times.
✓ Branch 1 taken 353330936 times.
371723461 if (mysql_fields[field].max_length < len)
3060 18392525 mysql_fields[field].max_length = len;
3061 }
3062 }
3063 }
3064 97250445 cur->data[field] = to; /* End of last field */
3065
3/4
✓ Branch 0 taken 97250451 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 107 times.
✓ Branch 3 taken 97250344 times.
97250445 if ((pkt_len = cli_safe_read(mysql, &is_data_packet)) == packet_error) {
3066
1/2
✓ Branch 0 taken 107 times.
✗ Branch 1 not taken.
107 free_rows(result);
3067 107 return nullptr;
3068 }
3069 }
3070 8958882 *prev_ptr = nullptr; /* last pointer is null */
3071 /* read EOF packet or OK packet if it is new client */
3072
1/2
✓ Branch 0 taken 8958882 times.
✗ Branch 1 not taken.
8958882 if (pkt_len > 1) {
3073
2/4
✓ Branch 0 taken 8958882 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8958882 times.
✗ Branch 3 not taken.
8958882 if (mysql->server_capabilities & CLIENT_DEPRECATE_EOF && !is_data_packet)
3074
1/2
✓ Branch 0 taken 8958882 times.
✗ Branch 1 not taken.
8958882 read_ok_ex(mysql, pkt_len);
3075 else {
3076 mysql->warning_count = uint2korr(cp + 1);
3077 mysql->server_status = uint2korr(cp + 3);
3078 }
3079
3080
3/8
✓ Branch 0 taken 8958882 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8958882 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8958882 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
8958882 DBUG_PRINT("info", ("status: %u warning_count: %u", mysql->server_status,
3081 mysql->warning_count));
3082 }
3083
3084 #if defined(CLIENT_PROTOCOL_TRACING)
3085
2/2
✓ Branch 0 taken 700997 times.
✓ Branch 1 taken 8220504 times.
8921501 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
3086
2/10
✓ Branch 0 taken 700997 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 700997 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
700997 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
3087 else
3088
3/10
✓ Branch 0 taken 8220503 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8220503 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
8220504 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
3089 #endif
3090
3/8
✓ Branch 0 taken 8958881 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8958881 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8958881 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
8958880 DBUG_PRINT("exit", ("Got %lu rows", (ulong)result->rows));
3091 8958881 return result;
3092 8963003 }
3093
3094 27273110 static int read_one_row_complete(MYSQL *mysql, ulong pkt_len,
3095 bool is_data_packet, uint fields,
3096 MYSQL_ROW row, ulong *lengths) {
3097
1/2
✓ Branch 0 taken 27273108 times.
✗ Branch 1 not taken.
27273110 DBUG_TRACE;
3098 uint field;
3099 ulong len;
3100 uchar *pos, *prev_pos, *end_pos;
3101 27273108 NET *net = &mysql->net;
3102
3103
4/4
✓ Branch 0 taken 27272967 times.
✓ Branch 1 taken 141 times.
✓ Branch 2 taken 43389 times.
✓ Branch 3 taken 27229578 times.
27273108 if (net->read_pos[0] != 0x00 && !is_data_packet) {
3104
1/2
✓ Branch 0 taken 43389 times.
✗ Branch 1 not taken.
43389 if (pkt_len > 1) /* MySQL 4.1 protocol */
3105 {
3106
1/2
✓ Branch 0 taken 43389 times.
✗ Branch 1 not taken.
43389 if (mysql->server_capabilities & CLIENT_DEPRECATE_EOF)
3107
1/2
✓ Branch 0 taken 43390 times.
✗ Branch 1 not taken.
43389 read_ok_ex(mysql, pkt_len);
3108 else {
3109 mysql->warning_count = uint2korr(net->read_pos + 1);
3110 mysql->server_status = uint2korr(net->read_pos + 3);
3111 }
3112 }
3113 #if defined(CLIENT_PROTOCOL_TRACING)
3114
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 43384 times.
43390 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
3115
2/10
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
6 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
3116 else
3117
2/10
✓ Branch 0 taken 43384 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 43384 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
43384 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
3118 #endif
3119 43390 return 1; /* End of data */
3120 }
3121 27229719 prev_pos = nullptr; /* allowed to write at packet[-1] */
3122 27229719 pos = net->read_pos;
3123 27229719 end_pos = pos + pkt_len;
3124
2/2
✓ Branch 0 taken 189586694 times.
✓ Branch 1 taken 27229671 times.
216816365 for (field = 0; field < fields; field++) {
3125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 189586694 times.
189586694 if (pos >= end_pos) {
3126 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
3127 return -1;
3128 }
3129
1/2
✓ Branch 0 taken 189586703 times.
✗ Branch 1 not taken.
189586694 len = (ulong)net_field_length_checked(&pos, (ulong)(end_pos - pos));
3130
3131
2/4
✓ Branch 0 taken 189586697 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 189586697 times.
189586703 DBUG_EXECUTE_IF("simulate_bad_field_length_1", { len = 1000000L; });
3132
2/4
✓ Branch 0 taken 189586646 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 189586646 times.
189586697 DBUG_EXECUTE_IF("simulate_bad_field_length_2", { len = pkt_len - 1; });
3133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 189586646 times.
189586646 if (pos > end_pos) {
3134 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
3135 return -1;
3136 }
3137
3138
2/2
✓ Branch 0 taken 47081 times.
✓ Branch 1 taken 189539565 times.
189586646 if (len == NULL_LENGTH) {
3139 47081 row[field] = nullptr;
3140 47081 *lengths++ = 0;
3141 } else {
3142 189539565 row[field] = (char *)pos;
3143 189539565 pos += len;
3144 189539565 *lengths++ = len;
3145 }
3146 /*
3147 It's safe to write to prev_pos here because we already check
3148 for a valid pos in the beginning of this loop.
3149 */
3150
2/2
✓ Branch 0 taken 162356992 times.
✓ Branch 1 taken 27229654 times.
189586646 if (prev_pos) *prev_pos = 0; /* Terminate prev field */
3151 189586646 prev_pos = pos;
3152 }
3153 27229671 row[field] = (char *)prev_pos + 1; /* End of last field */
3154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27229671 times.
27229671 if (prev_pos < end_pos) *prev_pos = 0; /* Terminate last field */
3155 27229671 return 0;
3156 27273061 }
3157
3158 /*
3159 Read one row. Uses packet buffer as storage for fields.
3160 When next packet is read, the previous field values are destroyed
3161 */
3162
3163 27272966 static int read_one_row(MYSQL *mysql, uint fields, MYSQL_ROW row,
3164 ulong *lengths) {
3165 ulong pkt_len;
3166 bool is_data_packet;
3167
3168
2/4
✓ Branch 0 taken 27272970 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27272970 times.
27272966 if ((pkt_len = cli_safe_read(mysql, &is_data_packet)) == packet_error)
3169 return -1;
3170
3171
1/2
✓ Branch 0 taken 27272972 times.
✗ Branch 1 not taken.
27272970 return read_one_row_complete(mysql, pkt_len, is_data_packet, fields, row,
3172 27272972 lengths);
3173 }
3174
3175 141 static net_async_status read_one_row_nonblocking(MYSQL *mysql, uint fields,
3176 MYSQL_ROW row, ulong *lengths,
3177 int *res) {
3178
1/2
✓ Branch 0 taken 141 times.
✗ Branch 1 not taken.
141 DBUG_TRACE;
3179 ulong pkt_len;
3180 bool is_data_packet;
3181 net_async_status status;
3182
3183
1/2
✓ Branch 0 taken 141 times.
✗ Branch 1 not taken.
141 status = cli_safe_read_nonblocking(mysql, &is_data_packet, &pkt_len);
3184
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 141 times.
141 if (status == NET_ASYNC_NOT_READY) {
3185 return status;
3186 }
3187
3188 141 mysql->packet_length = pkt_len;
3189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 141 times.
141 if (pkt_len == packet_error) {
3190 *res = -1;
3191 return NET_ASYNC_COMPLETE;
3192 }
3193
3194
1/2
✓ Branch 0 taken 141 times.
✗ Branch 1 not taken.
141 *res = read_one_row_complete(mysql, pkt_len, is_data_packet, fields, row,
3195 lengths);
3196 141 return NET_ASYNC_COMPLETE;
3197 141 }
3198
3199 /****************************************************************************
3200 Init MySQL structure or allocate one
3201 ****************************************************************************/
3202
3203 477719 MYSQL *STDCALL mysql_init(MYSQL *mysql) {
3204
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 477730 times.
477719 if (mysql_server_init(0, nullptr, nullptr)) return nullptr;
3205
2/2
✓ Branch 0 taken 23524 times.
✓ Branch 1 taken 454206 times.
477730 if (!mysql) {
3206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23496 times.
23524 if (!(mysql = (MYSQL *)my_malloc(key_memory_MYSQL, sizeof(*mysql),
3207 MYF(MY_WME | MY_ZEROFILL)))) {
3208 set_mysql_error(nullptr, CR_OUT_OF_MEMORY, unknown_sqlstate);
3209 return nullptr;
3210 }
3211 23496 mysql->free_me = true;
3212 } else
3213 454206 memset(mysql, 0, sizeof(*(mysql)));
3214 477702 mysql->charset = default_client_charset_info;
3215 477702 mysql->field_alloc = (MEM_ROOT *)my_malloc(
3216 key_memory_MYSQL, sizeof(*mysql->field_alloc), MYF(MY_WME | MY_ZEROFILL));
3217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 477723 times.
477723 if (!mysql->field_alloc) {
3218 set_mysql_error(nullptr, CR_OUT_OF_MEMORY, unknown_sqlstate);
3219 if (mysql->free_me) my_free(mysql);
3220 return nullptr;
3221 }
3222 477723 my_stpcpy(mysql->net.sqlstate, not_error_sqlstate);
3223
3224 /*
3225 Only enable LOAD DATA INFILE by default if configured with option
3226 ENABLED_LOCAL_INFILE
3227 */
3228
3229 #if defined(ENABLED_LOCAL_INFILE) && !defined(MYSQL_SERVER)
3230 mysql->options.client_flag |= CLIENT_LOCAL_FILES;
3231 #endif
3232
3233 #if defined(_WIN32)
3234 mysql->options.shared_memory_base_name = my_strdup(
3235 key_memory_mysql_options, def_shared_memory_base_name, MYF(MY_WME));
3236 #endif
3237
3238 477703 mysql->options.report_data_truncation = true; /* default */
3239
3240 /* Initialize extensions. */
3241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 477725 times.
477703 if (!(mysql->extension = mysql_extension_init(mysql))) {
3242 set_mysql_error(nullptr, CR_OUT_OF_MEMORY, unknown_sqlstate);
3243 return nullptr;
3244 }
3245
3246 /*
3247 By default we don't reconnect because it could silently corrupt data (after
3248 reconnection you potentially lose table locks, user variables, session
3249 variables (transactions but they are specifically dealt with in
3250 mysql_reconnect()).
3251 This is a change: < 5.0.3 mysql->reconnect was set to 1 by default.
3252 How this change impacts existing apps:
3253 - existing apps which relied on the default will see a behaviour change;
3254 they will have to set reconnect=1 after mysql_real_connect().
3255 - existing apps which explicitly asked for reconnection (the only way they
3256 could do it was by setting mysql.reconnect to 1 after mysql_real_connect())
3257 will not see a behaviour change.
3258 - existing apps which explicitly asked for no reconnection
3259 (mysql.reconnect=0) will not see a behaviour change.
3260 */
3261 477725 mysql->reconnect = false;
3262 #if !defined(MYSQL_SERVER)
3263
2/2
✓ Branch 0 taken 467045 times.
✓ Branch 1 taken 5 times.
467050 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
3264 467040 mysql->options.extension->ssl_mode = SSL_MODE_PREFERRED;
3265 #endif
3266 /* by default connection_compressed should be OFF */
3267
2/2
✓ Branch 0 taken 10675 times.
✓ Branch 1 taken 467040 times.
477715 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
3268 477715 mysql->options.extension->connection_compressed = false;
3269
3270 477715 mysql->resultset_metadata = RESULTSET_METADATA_FULL;
3271
3/4
✓ Branch 0 taken 477715 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 477713 times.
✓ Branch 3 taken 2 times.
477715 ASYNC_DATA(mysql)->async_op_status = ASYNC_OP_UNSET;
3272 477713 return mysql;
3273 }
3274
3275 /*
3276 MYSQL::extension handling (see sql_common.h for declaration
3277 of MYSQL_EXTENSION structure).
3278 */
3279
3280 478566 MYSQL_EXTENSION *mysql_extension_init(MYSQL *mysql [[maybe_unused]]) {
3281 MYSQL_EXTENSION *ext;
3282
1/2
✓ Branch 0 taken 478588 times.
✗ Branch 1 not taken.
478566 DBUG_TRACE;
3283
3284
1/2
✓ Branch 0 taken 478586 times.
✗ Branch 1 not taken.
478588 ext = static_cast<MYSQL_EXTENSION *>(my_malloc(PSI_NOT_INSTRUMENTED,
3285 sizeof(MYSQL_EXTENSION),
3286 MYF(MY_WME | MY_ZEROFILL)));
3287 478580 ext->mysql_async_context = static_cast<MYSQL_ASYNC *>(
3288
1/2
✓ Branch 0 taken 478580 times.
✗ Branch 1 not taken.
478586 my_malloc(PSI_NOT_INSTRUMENTED, sizeof(struct MYSQL_ASYNC),
3289 MYF(MY_WME | MY_ZEROFILL)));
3290 /* set default value */
3291 478580 ext->mysql_async_context->async_op_status = ASYNC_OP_UNSET;
3292 #ifdef MYSQL_SERVER
3293 10962 ext->server_extn = nullptr;
3294 #endif
3295
3/8
✓ Branch 0 taken 478574 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 478571 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 478571 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
478580 DBUG_PRINT("async",
3296 ("set state=%d", ext->mysql_async_context->async_query_state));
3297 478586 return ext;
3298 478571 }
3299
3300 21260337 void mysql_extension_bind_free(MYSQL_EXTENSION *ext) {
3301
1/2
✓ Branch 0 taken 21260530 times.
✗ Branch 1 not taken.
21260337 DBUG_TRACE;
3302
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 21260491 times.
21260530 if (ext->bind_info.n_params) {
3303
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 my_free(ext->bind_info.bind);
3304
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 39 times.
82 for (uint idx = 0; idx < ext->bind_info.n_params; idx++)
3305
1/2
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
43 my_free(ext->bind_info.names[idx]);
3306
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 my_free(ext->bind_info.names);
3307 }
3308 21260530 memset(&ext->bind_info, 0, sizeof(ext->bind_info));
3309 21260530 }
3310
3311 478383 void mysql_extension_free(MYSQL_EXTENSION *ext) {
3312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 478383 times.
478383 if (!ext) return;
3313
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 478383 times.
478383 if (ext->trace_data) my_free(ext->trace_data);
3314
1/2
✓ Branch 0 taken 478384 times.
✗ Branch 1 not taken.
478383 if (ext->mysql_async_context) {
3315
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 478373 times.
478384 if (ext->mysql_async_context->connect_context) {
3316 11 if (ext->mysql_async_context->connect_context
3317
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
11 ->scramble_buffer_allocated) {
3318 7 my_free(ext->mysql_async_context->connect_context->scramble_buffer);
3319 7 ext->mysql_async_context->connect_context->scramble_buffer = nullptr;
3320 }
3321
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
11 if (ext->mysql_async_context->connect_context->ssl) {
3322 1 SSL_free(ext->mysql_async_context->connect_context->ssl);
3323 1 ext->mysql_async_context->connect_context->ssl = nullptr;
3324 }
3325 11 my_free(ext->mysql_async_context->connect_context);
3326 11 ext->mysql_async_context->connect_context = nullptr;
3327 }
3328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 478384 times.
478384 if (ext->mysql_async_context->async_qp_data) {
3329 my_free(ext->mysql_async_context->async_qp_data);
3330 ext->mysql_async_context->async_qp_data = nullptr;
3331 ext->mysql_async_context->async_qp_data_length = 0;
3332 }
3333 478384 my_free(ext->mysql_async_context);
3334 478394 ext->mysql_async_context = nullptr;
3335 }
3336 // free state change related resources.
3337 478393 free_state_change_info(ext);
3338 478384 mysql_extension_bind_free(ext);
3339 478418 my_free(ext);
3340 }
3341
3342 /*
3343 Fill in SSL part of MYSQL structure and set 'use_ssl' flag.
3344 NB! Errors are not reported until you do mysql_real_connect.
3345 */
3346
3347 134213 bool STDCALL mysql_ssl_set(MYSQL *mysql [[maybe_unused]],
3348 const char *key [[maybe_unused]],
3349 const char *cert [[maybe_unused]],
3350 const char *ca [[maybe_unused]],
3351 const char *capath [[maybe_unused]],
3352 const char *cipher [[maybe_unused]]) {
3353 134213 bool result = false;
3354
1/2
✓ Branch 0 taken 134213 times.
✗ Branch 1 not taken.
134213 DBUG_TRACE;
3355
1/2
✓ Branch 0 taken 134213 times.
✗ Branch 1 not taken.
134213 result = mysql_options(mysql, MYSQL_OPT_SSL_KEY, key) +
3356
1/2
✓ Branch 0 taken 134213 times.
✗ Branch 1 not taken.
134213 mysql_options(mysql, MYSQL_OPT_SSL_CERT, cert) +
3357
1/2
✓ Branch 0 taken 134213 times.
✗ Branch 1 not taken.
134213 mysql_options(mysql, MYSQL_OPT_SSL_CA, ca) +
3358
1/2
✓ Branch 0 taken 134213 times.
✗ Branch 1 not taken.
134213 mysql_options(mysql, MYSQL_OPT_SSL_CAPATH, capath) +
3359
1/2
✓ Branch 0 taken 134212 times.
✗ Branch 1 not taken.
134213 mysql_options(mysql, MYSQL_OPT_SSL_CIPHER, cipher)
3360 ? true
3361 : false;
3362 134213 return result;
3363 134212 }
3364
3365 /*
3366 Free strings in the SSL structure and clear 'use_ssl' flag.
3367 NB! Errors are not reported until you do mysql_real_connect.
3368 */
3369
3370 517174 static void mysql_ssl_free(MYSQL *mysql) {
3371
1/2
✓ Branch 0 taken 517242 times.
✗ Branch 1 not taken.
517174 DBUG_TRACE;
3372
3373
1/2
✓ Branch 0 taken 517242 times.
✗ Branch 1 not taken.
517242 my_free(mysql->options.ssl_key);
3374
1/2
✓ Branch 0 taken 517239 times.
✗ Branch 1 not taken.
517242 my_free(mysql->options.ssl_cert);
3375
1/2
✓ Branch 0 taken 517236 times.
✗ Branch 1 not taken.
517239 my_free(mysql->options.ssl_ca);
3376
1/2
✓ Branch 0 taken 517228 times.
✗ Branch 1 not taken.
517236 my_free(mysql->options.ssl_capath);
3377
1/2
✓ Branch 0 taken 517218 times.
✗ Branch 1 not taken.
517228 my_free(mysql->options.ssl_cipher);
3378
2/2
✓ Branch 0 taken 477542 times.
✓ Branch 1 taken 39676 times.
517218 if (mysql->options.extension) {
3379
1/2
✓ Branch 0 taken 477538 times.
✗ Branch 1 not taken.
477542 my_free(mysql->options.extension->tls_version);
3380
1/2
✓ Branch 0 taken 477523 times.
✗ Branch 1 not taken.
477538 my_free(mysql->options.extension->ssl_crl);
3381
1/2
✓ Branch 0 taken 477517 times.
✗ Branch 1 not taken.
477523 my_free(mysql->options.extension->ssl_crlpath);
3382
1/2
✓ Branch 0 taken 477522 times.
✗ Branch 1 not taken.
477517 my_free(mysql->options.extension->tls_ciphersuites);
3383
1/2
✓ Branch 0 taken 477524 times.
✗ Branch 1 not taken.
477522 my_free(mysql->options.extension->load_data_dir);
3384
2/2
✓ Branch 0 taken 1432525 times.
✓ Branch 1 taken 477547 times.
1910072 for (unsigned int idx = 0; idx < MAX_AUTHENTICATION_FACTOR; idx++) {
3385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1432525 times.
1432525 if (mysql->options.extension->client_auth_info[idx].plugin_name) {
3386 my_free(mysql->options.extension->client_auth_info[idx].plugin_name);
3387 mysql->options.extension->client_auth_info[idx].plugin_name = nullptr;
3388 }
3389
2/2
✓ Branch 0 taken 49585 times.
✓ Branch 1 taken 1382940 times.
1432525 if (mysql->options.extension->client_auth_info[idx].password) {
3390
1/2
✓ Branch 0 taken 49608 times.
✗ Branch 1 not taken.
49585 my_free(mysql->options.extension->client_auth_info[idx].password);
3391 49608 mysql->options.extension->client_auth_info[idx].password = nullptr;
3392 }
3393 }
3394 }
3395 517223 mysql->options.ssl_key = nullptr;
3396 517223 mysql->options.ssl_cert = nullptr;
3397 517223 mysql->options.ssl_ca = nullptr;
3398 517223 mysql->options.ssl_capath = nullptr;
3399 517223 mysql->options.ssl_cipher = nullptr;
3400
2/2
✓ Branch 0 taken 477544 times.
✓ Branch 1 taken 39679 times.
517223 if (mysql->options.extension) {
3401 477544 mysql->options.extension->ssl_crl = nullptr;
3402 477544 mysql->options.extension->ssl_crlpath = nullptr;
3403 477544 mysql->options.extension->ssl_ctx_flags = 0;
3404 477544 mysql->options.extension->tls_version = nullptr;
3405 477544 mysql->options.extension->ssl_mode = SSL_MODE_DISABLED;
3406 477544 mysql->options.extension->ssl_fips_mode = SSL_FIPS_MODE_OFF;
3407 477544 mysql->options.extension->tls_ciphersuites = nullptr;
3408 477544 mysql->options.extension->load_data_dir = nullptr;
3409 }
3410 517223 mysql->connector_fd = nullptr;
3411 517223 }
3412
3413 /*
3414 Return the SSL cipher (if any) used for current
3415 connection to the server.
3416
3417 SYNOPSIS
3418 mysql_get_ssl_cipher()
3419 mysql pointer to the mysql connection
3420
3421 */
3422
3423 22395 const char *STDCALL mysql_get_ssl_cipher(MYSQL *mysql [[maybe_unused]]) {
3424
1/2
✓ Branch 0 taken 22396 times.
✗ Branch 1 not taken.
22395 DBUG_TRACE;
3425
3/4
✓ Branch 0 taken 22396 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21999 times.
✓ Branch 3 taken 397 times.
22396 if (mysql->net.vio && mysql->net.vio->ssl_arg)
3426
2/4
✓ Branch 0 taken 21998 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21998 times.
✗ Branch 3 not taken.
21999 return SSL_get_cipher_name((SSL *)mysql->net.vio->ssl_arg);
3427 397 return nullptr;
3428 22395 }
3429
3430 #include <openssl/x509v3.h>
3431
3432 #if OPENSSL_VERSION_NUMBER < 0x10002000L
3433 /*
3434 Compares the DNS entry from the Subject Alternative Names (SAN) list with
3435 the provided host name
3436
3437 SYNOPSIS
3438 ssl_cmp_san_dns_name()
3439 dns_name pointer to a SAN list DNS entry
3440 host_name name of the server
3441 errptr if we fail, we'll return (a pointer to a string
3442 describing) the reason here
3443
3444 RETURN VALUES
3445 false Success
3446 true Failed to validate server
3447
3448 */
3449
3450 static bool ssl_cmp_san_dns_name(ASN1_STRING *dns_name, const char *host_name,
3451 const char **errptr) {
3452 DBUG_ENTER("ssl_cmp_san_dns_name");
3453 *errptr = nullptr;
3454 if (dns_name == nullptr) {
3455 *errptr = "Failed to get DNS name from SAN list item";
3456 DBUG_RETURN(true);
3457 }
3458 #if OPENSSL_VERSION_NUMBER < 0x10100000L
3459 const char *cn = reinterpret_cast<const char *>(
3460 const_cast<const unsigned char *>(ASN1_STRING_data(dns_name)));
3461 #else
3462 const char *cn = static_cast<const char *>(ASN1_STRING_get0_data(dns_name));
3463 #endif
3464 if (cn == nullptr) {
3465 *errptr = "Failed to get data from SAN DNS name";
3466 DBUG_RETURN(true);
3467 }
3468 // There should not be any NULL embedded in the DNS name
3469 if (static_cast<size_t>(ASN1_STRING_length(dns_name)) != strlen(cn)) {
3470 *errptr = "NULL embedded in the certificate SAN DNS name";
3471 DBUG_RETURN(true);
3472 }
3473 DBUG_PRINT("info", ("SAN DNS name in cert: %s", cn));
3474 if (!strcmp(cn, host_name)) DBUG_RETURN(false);
3475
3476 DBUG_RETURN(true);
3477 }
3478
3479 /*
3480 Compares the IP address entry from the Subject Alternative Names (SAN) list
3481 with the provided host IP address
3482
3483 SYNOPSIS
3484 ssl_cmp_san_ip_address()
3485 ip_address pointer to a SAN list IP address entry
3486 host_ip IP address of the server
3487 host_ip_len server IP address length (must be either 4 or 16)
3488 errptr if we fail, we'll return (a pointer to a string
3489 describing) the reason here
3490
3491 RETURN VALUES
3492 false Success
3493 true Failed to validate server
3494
3495 */
3496
3497 static bool ssl_cmp_san_ip_address(ASN1_OCTET_STRING *ip_address,
3498 const unsigned char *host_ip,
3499 size_t host_ip_len, const char **errptr) {
3500 DBUG_ENTER("ssl_cmp_san_ip_address");
3501 *errptr = nullptr;
3502 if (ip_address == nullptr) {
3503 *errptr = "Failed to get IP address from SAN list item";
3504 DBUG_RETURN(true);
3505 }
3506 const size_t ip_address_len = ASN1_STRING_length(ip_address);
3507 /* IP address length must be either 4 (IPV4) or 16 (IPV6) */
3508 if (ip_address_len != 4 && ip_address_len != 16) {
3509 *errptr = "Invalid IP address embedded in the certificate SAN IP address";
3510 DBUG_RETURN(true);
3511 }
3512 #if OPENSSL_VERSION_NUMBER < 0x10100000L
3513 const unsigned char *ip = ASN1_STRING_data(ip_address);
3514 #else
3515 const unsigned char *ip = ASN1_STRING_get0_data(ip_address);
3516 #endif
3517 if (ip == nullptr) {
3518 *errptr = "Failed to get data from SAN IP address";
3519 DBUG_RETURN(true);
3520 }
3521 DBUG_RETURN(!(ip_address_len == host_ip_len &&
3522 memcmp(host_ip, ip, host_ip_len) == 0));
3523 }
3524
3525 /*
3526 Check the certificate's Subject Alternative Names (SAN) against the
3527 hostname / IP address we connected to
3528
3529 SYNOPSIS
3530 ssl_verify_server_cert_san()
3531 server_cert pointer to a X509 certificate
3532 hostname_or_ip name of the server / pointer to a V4/V6 IP address
3533 buffer
3534 hostname_or_ip_len 0 for host name, 4/16 for ip address
3535 errptr if we fail, we'll return (a pointer to a string
3536 describing) the reason here
3537
3538 RETURN VALUES
3539 false Success
3540 true Failed to validate server
3541
3542 */
3543
3544 static bool ssl_verify_server_cert_san(X509 *server_cert,
3545 const char *hostname_or_ip,
3546 size_t hostname_or_ip_len,
3547 const char **errptr) {
3548 bool ret_validation = true;
3549
3550 DBUG_ENTER("ssl_verify_server_cert_san");
3551 *errptr = nullptr;
3552 GENERAL_NAMES *const sans = static_cast<GENERAL_NAMES *>(
3553 X509_get_ext_d2i(server_cert, NID_subject_alt_name, nullptr, nullptr));
3554 if (sans == nullptr) DBUG_RETURN(ret_validation);
3555
3556 const int number_of_sans = sk_GENERAL_NAME_num(sans);
3557 for (int i = 0; ret_validation != 0 && i < number_of_sans; ++i) {
3558 GENERAL_NAME *san = sk_GENERAL_NAME_value(sans, i);
3559 if (san == nullptr) {
3560 *errptr = "Failed to get item from SAN list";
3561 goto error;
3562 }
3563 if (hostname_or_ip_len == 0) {
3564 /* server host name was provided, check only GEN_DNS entries */
3565 if (san->type == GEN_DNS) {
3566 ret_validation =
3567 ssl_cmp_san_dns_name(san->d.dNSName, hostname_or_ip, errptr);
3568 if (*errptr != nullptr) goto error;
3569 }
3570 } else {
3571 /* server IP address was provided, check only GEN_IPADD entries */
3572 if (san->type == GEN_IPADD) {
3573 ret_validation = ssl_cmp_san_ip_address(
3574 san->d.iPAddress,
3575 reinterpret_cast<const unsigned char *>(hostname_or_ip),
3576 hostname_or_ip_len, errptr);
3577 if (*errptr != NULL) goto error;
3578 }
3579 }
3580 } /* iterating over SAN enries */
3581
3582 error:
3583 GENERAL_NAMES_free(sans);
3584
3585 DBUG_RETURN(ret_validation);
3586 }
3587
3588 #endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
3589
3590 /**
3591 Get the current SSL session serialization
3592
3593 Return the SSL session serialized (if any) used for current
3594 connection to the server.
3595 The caller needs to free the return value by calling @ref
3596 mysql_free_ssl_session_data()
3597
3598 @param mysql pointer to the mysql connection
3599 @param n_ticket the ticket to return. Currently on 0 is supported.
3600 @param[out] out_len if a non-null is supplied, stores the length of data
3601 returned.
3602 @retval null-terminated string of the session serialization
3603 @retval null pointer if not an SSL connection or error
3604 */
3605
3606 27799 void *STDCALL mysql_get_ssl_session_data(MYSQL *mysql, unsigned int n_ticket,
3607 unsigned int *out_len) {
3608
1/2
✓ Branch 0 taken 27799 times.
✗ Branch 1 not taken.
27799 DBUG_TRACE;
3609
3610 /* multiple TLS ticket not implemented yet */
3611
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27799 times.
27799 if (n_ticket != 0) return nullptr;
3612
3613 using raii_bio = std::unique_ptr<BIO, decltype(&BIO_free)>;
3614 using raii_sess = std::unique_ptr<SSL_SESSION, decltype(&SSL_SESSION_free)>;
3615
3616
4/4
✓ Branch 0 taken 27798 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 17154 times.
✓ Branch 3 taken 10644 times.
27799 if (!mysql->net.vio || !mysql->net.vio->ssl_arg) {
3617
1/2
✓ Branch 0 taken 17155 times.
✗ Branch 1 not taken.
17155 set_mysql_extended_error(
3618 mysql, CR_CANT_GET_SESSION_DATA, unknown_sqlstate,
3619 ER_CLIENT(CR_CANT_GET_SESSION_DATA),
3620
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17154 times.
17155 !mysql->net.vio ? "Not connected" : "Not a TLS connection");
3621 17155 return nullptr;
3622 }
3623 raii_sess sess(
3624 10644 SSL_get1_session(reinterpret_cast<SSL *>(mysql->net.vio->ssl_arg)),
3625
1/2
✓ Branch 0 taken 10644 times.
✗ Branch 1 not taken.
10644 &SSL_SESSION_free);
3626
6/8
✓ Branch 0 taken 10644 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10644 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 10636 times.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 10636 times.
10644 if (!sess || !SSL_SESSION_is_resumable(sess.get())) {
3627
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 set_mysql_extended_error(
3628 mysql, CR_CANT_GET_SESSION_DATA, unknown_sqlstate,
3629 ER_CLIENT(CR_CANT_GET_SESSION_DATA),
3630
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 !sess ? "no session returned" : "session returned not resumable");
3631 8 return nullptr;
3632 }
3633
3634
2/4
✓ Branch 0 taken 10636 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10636 times.
✗ Branch 3 not taken.
10636 raii_bio bio(BIO_new(BIO_s_mem()), &BIO_free);
3635
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10636 times.
10636 if (!bio) {
3636 set_mysql_extended_error(mysql, CR_CANT_GET_SESSION_DATA, unknown_sqlstate,
3637 ER_CLIENT(CR_CANT_GET_SESSION_DATA),
3638 "Can't create the session data encoding object");
3639 return nullptr;
3640 }
3641
2/4
✓ Branch 0 taken 10636 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10636 times.
10636 if (0 == PEM_write_bio_SSL_SESSION(bio.get(), sess.get())) {
3642 set_mysql_extended_error(mysql, CR_CANT_GET_SESSION_DATA, unknown_sqlstate,
3643 ER_CLIENT(CR_CANT_GET_SESSION_DATA),
3644 "Can't encode the session data");
3645 return nullptr;
3646 }
3647
3648 10636 BUF_MEM *mem = nullptr;
3649
1/2
✓ Branch 0 taken 10636 times.
✗ Branch 1 not taken.
10636 BIO_get_mem_ptr(bio.get(), &mem);
3650
2/4
✓ Branch 0 taken 10636 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10636 times.
10636 if (!mem || mem->length == 0) {
3651 set_mysql_extended_error(mysql, CR_CANT_GET_SESSION_DATA, unknown_sqlstate,
3652 ER_CLIENT(CR_CANT_GET_SESSION_DATA),
3653 "Can't get a pointer to the session data");
3654 return nullptr;
3655 }
3656 char *ret = reinterpret_cast<char *>(
3657
1/2
✓ Branch 0 taken 10636 times.
✗ Branch 1 not taken.
10636 my_malloc(key_memory_MYSQL_ssl_session_data, mem->length + 1, MYF(0)));
3658 10636 memcpy(ret, mem->data, mem->length);
3659 10636 ret[mem->length] = 0;
3660
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10635 times.
10636 if (out_len) *out_len = static_cast<unsigned int>(mem->length);
3661 10636 return ret;
3662 27799 }
3663
3664 42977 static SSL_SESSION *ssl_session_deserialize_from_data_ptr(MYSQL *, char *data) {
3665 using raii_bio = std::unique_ptr<BIO, decltype(&BIO_free)>;
3666
2/2
✓ Branch 0 taken 10678 times.
✓ Branch 1 taken 32299 times.
42977 if (data != nullptr) {
3667 10678 SSL_SESSION *ret = nullptr;
3668
1/2
✓ Branch 0 taken 10678 times.
✗ Branch 1 not taken.
10678 raii_bio bio(BIO_new_mem_buf(data, strlen(data)), &BIO_free);
3669
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10678 times.
10678 if (!bio) return ret;
3670
1/2
✓ Branch 0 taken 10678 times.
✗ Branch 1 not taken.
10678 ret = PEM_read_bio_SSL_SESSION(bio.get(), &ret, nullptr, nullptr);
3671
4/8
✓ Branch 0 taken 10678 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10678 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10678 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 10678 times.
10678 if (ret && !SSL_SESSION_is_resumable(ret)) {
3672 if (ret) SSL_SESSION_free(ret);
3673 ret = nullptr;
3674 }
3675 10678 return ret;
3676 10678 }
3677 32299 return nullptr;
3678 }
3679
3680 /**
3681 Free a saved SSL session serialization
3682
3683 Frees the session serialization as returned by @ref
3684 mysql_get_ssl_session_data()
3685
3686 @param mysql pointer to the mysql connection
3687 @param data the session data to dispose of
3688 @retval true failure
3689 @retval false success
3690 */
3691
3692 10636 bool STDCALL mysql_free_ssl_session_data(MYSQL *mysql, void *data) {
3693 10636 SSL_SESSION *ses = ssl_session_deserialize_from_data_ptr(
3694 mysql, reinterpret_cast<char *>(data));
3695 10636 my_free(data);
3696
1/2
✓ Branch 0 taken 10636 times.
✗ Branch 1 not taken.
10636 if (ses) {
3697 10636 SSL_SESSION_free(ses);
3698 10636 return false;
3699 } else
3700 return true;
3701 }
3702
3703 /**
3704 Check if the current ssl session is reused
3705
3706 @param mysql pointer to the mysql connection
3707 @retval false not SSL or session not reused
3708 @retval true session reused
3709 */
3710
3711 36 bool STDCALL mysql_get_ssl_session_reused(MYSQL *mysql) {
3712
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 DBUG_TRACE;
3713
3/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 2 times.
36 if (mysql->net.vio && mysql->net.vio->ssl_arg) {
3714 68 return SSL_session_reused(
3715
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 reinterpret_cast<SSL *>(mysql->net.vio->ssl_arg)) != 0;
3716 }
3717 2 return false;
3718 36 }
3719
3720 /*
3721 Check the server's (subject) Common Name against the
3722 hostname we connected to
3723
3724 SYNOPSIS
3725 ssl_verify_server_cert()
3726 vio pointer to a SSL connected vio
3727 server_hostname name of the server that we connected to
3728 errptr if we fail, we'll return (a pointer to a string
3729 describing) the reason here
3730
3731 RETURN VALUES
3732 0 Success
3733 1 Failed to validate server
3734
3735 */
3736 22 static int ssl_verify_server_cert(Vio *vio, const char *server_hostname,
3737 const char **errptr) {
3738 SSL *ssl;
3739 22 X509 *server_cert = nullptr;
3740 #if OPENSSL_VERSION_NUMBER < 0x10002000L
3741 char *cn = NULL;
3742 int cn_loc = -1;
3743 ASN1_STRING *cn_asn1 = NULL;
3744 X509_NAME_ENTRY *cn_entry = NULL;
3745 X509_NAME *subject = NULL;
3746 const unsigned char *ipout = nullptr;
3747 size_t iplen = 0;
3748 #endif
3749 22 ASN1_OCTET_STRING *server_ip_address = nullptr;
3750 22 int ret_validation = 1;
3751
3752
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 DBUG_TRACE;
3753
3/8
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
22 DBUG_PRINT("enter", ("server_hostname: %s", server_hostname));
3754
3755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (!(ssl = (SSL *)vio->ssl_arg)) {
3756 *errptr = "No SSL pointer found";
3757 goto error;
3758 }
3759
3760
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (!server_hostname) {
3761 *errptr = "No server hostname supplied";
3762 goto error;
3763 }
3764
3765
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 if (!(server_cert = SSL_get_peer_certificate(ssl))) {
3766 *errptr = "Could not get server certificate";
3767 goto error;
3768 }
3769
3770
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 if (X509_V_OK != SSL_get_verify_result(ssl)) {
3771 *errptr = "Failed to verify the server certificate";
3772 goto error;
3773 }
3774 /*
3775 We already know that the certificate exchanged was valid; the SSL library
3776 handled that. Now we need to verify that the contents of the certificate
3777 are what we expect.
3778 */
3779
3780 /* Use OpenSSL certificate matching functions instead of our own if we
3781 have OpenSSL. The X509_check_* functions return 1 on success.
3782 */
3783 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
3784 /*
3785 For OpenSSL 1.0.2 and up we already set certificate verification
3786 parameters in the new_VioSSLFd() to perform automatic checks.
3787 */
3788 22 ret_validation = 0;
3789 #else /* OPENSSL_VERSION_NUMBER < 0x10002000L */
3790 /* Checking if the provided server_hostname is a V4/V6 IP address */
3791 server_ip_address = a2i_IPADDRESS(server_hostname);
3792 if (server_ip_address != nullptr) {
3793 iplen = ASN1_STRING_length(server_ip_address);
3794 ipout = (const unsigned char *)ASN1_STRING_data(server_ip_address);
3795 }
3796
3797 ret_validation = ssl_verify_server_cert_san(
3798 server_cert, iplen != 0 ? (const char *)ipout : server_hostname, iplen,
3799 errptr);
3800 if (*errptr != nullptr) goto error;
3801 if (ret_validation != 0) {
3802 /*
3803 OpenSSL prior to 1.0.2 do not support X509_check_host() function.
3804 Use deprecated X509_get_subject_name() instead.
3805 */
3806 subject = X509_get_subject_name(server_cert);
3807 // Find the CN location in the subject
3808 cn_loc = X509_NAME_get_index_by_NID(subject, NID_commonName, -1);
3809 if (cn_loc < 0) {
3810 *errptr = "Failed to get CN location in the certificate subject";
3811 goto error;
3812 }
3813
3814 // Get the CN entry for given location
3815 cn_entry = X509_NAME_get_entry(subject, cn_loc);
3816 if (cn_entry == nullptr) {
3817 *errptr = "Failed to get CN entry using CN location";
3818 goto error;
3819 }
3820
3821 // Get CN from common name entry
3822 cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry);
3823 if (cn_asn1 == nullptr) {
3824 *errptr = "Failed to get CN from CN entry";
3825 goto error;
3826 }
3827
3828 cn = reinterpret_cast<char *>(ASN1_STRING_data(cn_asn1));
3829 if (cn == nullptr) {
3830 *errptr = "Failed to get data from CN";
3831 goto error;
3832 }
3833
3834 // There should not be any NULL embedded in the CN
3835 if (static_cast<size_t>(ASN1_STRING_length(cn_asn1)) != strlen(cn)) {
3836 *errptr = "NULL embedded in the certificate CN";
3837 goto error;
3838 }
3839
3840 DBUG_PRINT("info", ("Server hostname in cert: %s", cn));
3841 if (!strcmp(cn, server_hostname)) {
3842 /* Success */
3843 ret_validation = 0;
3844 }
3845 }
3846 #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
3847
3848
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 *errptr = ret_validation != 0 ? "SSL certificate validation failure" : "";
3849
3850 22 error:
3851
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
22 if (server_ip_address != nullptr) ASN1_OCTET_STRING_free(server_ip_address);
3852
3853
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
22 if (server_cert != nullptr) X509_free(server_cert);
3854 22 return ret_validation;
3855 22 }
3856
3857 /*
3858 Note that the mysql argument must be initialized with mysql_init()
3859 before calling mysql_real_connect !
3860 */
3861
3862 static bool cli_read_query_result(MYSQL *mysql);
3863 static net_async_status cli_read_query_result_nonblocking(MYSQL *mysql);
3864 static MYSQL_RES *cli_use_result(MYSQL *mysql);
3865
3866 182362 int cli_read_change_user_result(MYSQL *mysql) {
3867 182362 return cli_safe_read(mysql, nullptr);
3868 }
3869
3870 25730 net_async_status cli_read_change_user_result_nonblocking(MYSQL *mysql,
3871 ulong *ret) {
3872 25730 return cli_safe_read_nonblocking(mysql, nullptr, ret);
3873 }
3874
3875 static MYSQL_METHODS client_methods = {
3876 cli_read_query_result, /* read_query_result */
3877 cli_advanced_command, /* advanced_command */
3878 cli_read_rows, /* read_rows */
3879 cli_use_result, /* use_result */
3880 cli_fetch_lengths, /* fetch_lengths */
3881 cli_flush_use_result, /* flush_use_result */
3882 cli_read_change_user_result /* read_change_user_result */
3883 #ifndef MYSQL_SERVER
3884 ,
3885 cli_list_fields, /* list_fields */
3886 cli_read_prepare_result, /* read_prepare_result */
3887 cli_stmt_execute, /* stmt_execute */
3888 cli_read_binary_rows, /* read_binary_rows */
3889 cli_unbuffered_fetch, /* unbuffered_fetch */
3890 cli_read_statistics, /* read_statistics */
3891 cli_read_query_result, /* next_result */
3892 cli_read_binary_rows, /* read_rows_from_cursor */
3893 free_rows
3894 #endif
3895 ,
3896 cli_read_query_result_nonblocking, /* read_query_result_nonblocking */
3897 cli_advanced_command_nonblocking, /* advanced_command_nonblocking */
3898 cli_read_rows_nonblocking, /* read_rows_nonblocking */
3899 cli_flush_use_result_nonblocking, /* flush_use_result_nonblocking */
3900 cli_read_query_result_nonblocking, /* next_result_nonblocking */
3901 cli_read_change_user_result_nonblocking /* read_change_user_result_nonblocking
3902 */
3903 };
3904
3905 typedef enum my_cs_match_type_enum {
3906 /* MySQL and OS charsets are fully compatible */
3907 my_cs_exact,
3908 /* MySQL charset is very close to OS charset */
3909 my_cs_approx,
3910 /*
3911 MySQL knows this charset, but it is not supported as client character set.
3912 */
3913 my_cs_unsupp
3914 } my_cs_match_type;
3915
3916 struct MY_CSET_OS_NAME {
3917 const char *os_name;
3918 const char *my_name;
3919 my_cs_match_type param;
3920 };
3921
3922 const MY_CSET_OS_NAME charsets[] = {
3923 #ifdef _WIN32
3924 {"cp437", "cp850", my_cs_approx}, {"cp850", "cp850", my_cs_exact},
3925 {"cp852", "cp852", my_cs_exact}, {"cp858", "cp850", my_cs_approx},
3926 {"cp866", "cp866", my_cs_exact}, {"cp874", "tis620", my_cs_approx},
3927 {"cp932", "cp932", my_cs_exact}, {"cp936", "gbk", my_cs_approx},
3928 {"cp949", "euckr", my_cs_approx}, {"cp950", "big5", my_cs_exact},
3929 {"cp1200", "utf16le", my_cs_unsupp}, {"cp1201", "utf16", my_cs_unsupp},
3930 {"cp1250", "cp1250", my_cs_exact}, {"cp1251", "cp1251", my_cs_exact},
3931 {"cp1252", "latin1", my_cs_exact}, {"cp1253", "greek", my_cs_exact},
3932 {"cp1254", "latin5", my_cs_exact}, {"cp1255", "hebrew", my_cs_approx},
3933 {"cp1256", "cp1256", my_cs_exact}, {"cp1257", "cp1257", my_cs_exact},
3934 {"cp10000", "macroman", my_cs_exact}, {"cp10001", "sjis", my_cs_approx},
3935 {"cp10002", "big5", my_cs_approx}, {"cp10008", "gb2312", my_cs_approx},
3936 {"cp10021", "tis620", my_cs_approx}, {"cp10029", "macce", my_cs_exact},
3937 {"cp12001", "utf32", my_cs_unsupp}, {"cp20107", "swe7", my_cs_exact},
3938 {"cp20127", "latin1", my_cs_approx}, {"cp20866", "koi8r", my_cs_exact},
3939 {"cp20932", "ujis", my_cs_exact}, {"cp20936", "gb2312", my_cs_approx},
3940 {"cp20949", "euckr", my_cs_approx}, {"cp21866", "koi8u", my_cs_exact},
3941 {"cp28591", "latin1", my_cs_approx}, {"cp28592", "latin2", my_cs_exact},
3942 {"cp28597", "greek", my_cs_exact}, {"cp28598", "hebrew", my_cs_exact},
3943 {"cp28599", "latin5", my_cs_exact}, {"cp28603", "latin7", my_cs_exact},
3944 {"cp38598", "hebrew", my_cs_exact}, {"cp51932", "ujis", my_cs_exact},
3945 {"cp51936", "gb2312", my_cs_exact}, {"cp51949", "euckr", my_cs_exact},
3946 {"cp51950", "big5", my_cs_exact}, {"cp54936", "gb18030", my_cs_exact},
3947 {"cp65001", "utf8mb4", my_cs_exact},
3948
3949 #else /* not Windows */
3950
3951 {"646", "latin1", my_cs_approx}, /* Default on Solaris */
3952 {"ANSI_X3.4-1968", "latin1", my_cs_approx},
3953 {"ansi1251", "cp1251", my_cs_exact},
3954 {"armscii8", "armscii8", my_cs_exact},
3955 {"armscii-8", "armscii8", my_cs_exact},
3956 {"ASCII", "latin1", my_cs_approx},
3957 {"Big5", "big5", my_cs_exact},
3958 {"cp1251", "cp1251", my_cs_exact},
3959 {"cp1255", "hebrew", my_cs_approx},
3960 {"CP866", "cp866", my_cs_exact},
3961 {"eucCN", "gb2312", my_cs_exact},
3962 {"euc-CN", "gb2312", my_cs_exact},
3963 {"eucJP", "ujis", my_cs_exact},
3964 {"euc-JP", "ujis", my_cs_exact},
3965 {"eucKR", "euckr", my_cs_exact},
3966 {"euc-KR", "euckr", my_cs_exact},
3967 {"gb18030", "gb18030", my_cs_exact},
3968 {"gb2312", "gb2312", my_cs_exact},
3969 {"gbk", "gbk", my_cs_exact},
3970 {"georgianps", "geostd8", my_cs_exact},
3971 {"georgian-ps", "geostd8", my_cs_exact},
3972 {"IBM-1252", "cp1252", my_cs_exact},
3973
3974 {"iso88591", "latin1", my_cs_approx},
3975 {"ISO_8859-1", "latin1", my_cs_approx},
3976 {"ISO8859-1", "latin1", my_cs_approx},
3977 {"ISO-8859-1", "latin1", my_cs_approx},
3978
3979 {"iso885913", "latin7", my_cs_exact},
3980 {"ISO_8859-13", "latin7", my_cs_exact},
3981 {"ISO8859-13", "latin7", my_cs_exact},
3982 {"ISO-8859-13", "latin7", my_cs_exact},
3983
3984 {"iso88592", "latin2", my_cs_exact},
3985 {"ISO_8859-2", "latin2", my_cs_exact},
3986 {"ISO8859-2", "latin2", my_cs_exact},
3987 {"ISO-8859-2", "latin2", my_cs_exact},
3988
3989 {"iso88597", "greek", my_cs_exact},
3990 {"ISO_8859-7", "greek", my_cs_exact},
3991 {"ISO8859-7", "greek", my_cs_exact},
3992 {"ISO-8859-7", "greek", my_cs_exact},
3993
3994 {"iso88598", "hebrew", my_cs_exact},
3995 {"ISO_8859-8", "hebrew", my_cs_exact},
3996 {"ISO8859-8", "hebrew", my_cs_exact},
3997 {"ISO-8859-8", "hebrew", my_cs_exact},
3998
3999 {"iso88599", "latin5", my_cs_exact},
4000 {"ISO_8859-9", "latin5", my_cs_exact},
4001 {"ISO8859-9", "latin5", my_cs_exact},
4002 {"ISO-8859-9", "latin5", my_cs_exact},
4003
4004 {"koi8r", "koi8r", my_cs_exact},
4005 {"KOI8-R", "koi8r", my_cs_exact},
4006 {"koi8u", "koi8u", my_cs_exact},
4007 {"KOI8-U", "koi8u", my_cs_exact},
4008
4009 {"roman8", "hp8", my_cs_exact}, /* Default on HP UX */
4010
4011 {"Shift_JIS", "sjis", my_cs_exact},
4012 {"SJIS", "sjis", my_cs_exact},
4013 {"shiftjisx0213", "sjis", my_cs_exact},
4014
4015 {"tis620", "tis620", my_cs_exact},
4016 {"tis-620", "tis620", my_cs_exact},
4017
4018 {"ujis", "ujis", my_cs_exact},
4019
4020 {"US-ASCII", "latin1", my_cs_approx},
4021
4022 {"utf8", "utf8mb4", my_cs_exact},
4023 {"utf-8", "utf8mb4", my_cs_exact},
4024 #endif
4025 {nullptr, nullptr, my_cs_exact}};
4026
4027 5331 const char *my_os_charset_to_mysql_charset(const char *csname) {
4028 const MY_CSET_OS_NAME *csp;
4029
1/2
✓ Branch 0 taken 10662 times.
✗ Branch 1 not taken.
10662 for (csp = charsets; csp->os_name; csp++) {
4030
2/2
✓ Branch 0 taken 5331 times.
✓ Branch 1 taken 5331 times.
10662 if (!my_strcasecmp(&my_charset_latin1, csp->os_name, csname)) {
4031
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 5331 times.
✗ Branch 2 not taken.
5331 switch (csp->param) {
4032 case my_cs_exact:
4033 return csp->my_name;
4034
4035 5331 case my_cs_approx:
4036 /*
4037 Maybe we should print a warning eventually:
4038 character set correspondence is not exact.
4039 */
4040 5331 return csp->my_name;
4041
4042 default:
4043 my_printf_error(ER_UNKNOWN_ERROR,
4044 "OS character set '%s'"
4045 " is not supported by MySQL client",
4046 MYF(0), csp->my_name);
4047 goto def;
4048 }
4049 }
4050 }
4051
4052 my_printf_error(ER_UNKNOWN_ERROR, "Unknown OS character set '%s'.", MYF(0),
4053 csname);
4054
4055 def:
4056 csname = MYSQL_DEFAULT_CHARSET_NAME;
4057 my_printf_error(ER_UNKNOWN_ERROR,
4058 "Switching to the default character set '%s'.", MYF(0),
4059 csname);
4060 return csname;
4061 }
4062
4063 #ifndef _WIN32
4064 #include <stdlib.h> /* for getenv() */
4065 #ifdef HAVE_LANGINFO_H
4066 #include <langinfo.h>
4067 #endif
4068 #include <locale.h>
4069 #endif /* _WIN32 */
4070
4071 5331 static int mysql_autodetect_character_set(MYSQL *mysql) {
4072 5331 const char *csname = MYSQL_DEFAULT_CHARSET_NAME;
4073
4074 #ifdef _WIN32
4075 char cpbuf[64];
4076 {
4077 snprintf(cpbuf, sizeof(cpbuf), "cp%d", (int)GetConsoleCP());
4078 csname = my_os_charset_to_mysql_charset(cpbuf);
4079 }
4080 #elif defined(HAVE_NL_LANGINFO)
4081 {
4082
3/6
✓ Branch 0 taken 5331 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5331 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5331 times.
✗ Branch 5 not taken.
5331 if (setlocale(LC_CTYPE, "") && (csname = nl_langinfo(CODESET)))
4083 5331 csname = my_os_charset_to_mysql_charset(csname);
4084 }
4085 #endif
4086
4087
1/2
✓ Branch 0 taken 5331 times.
✗ Branch 1 not taken.
5331 if (mysql->options.charset_name) my_free(mysql->options.charset_name);
4088 5331 if (!(mysql->options.charset_name =
4089
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5331 times.
5331 my_strdup(key_memory_mysql_options, csname, MYF(MY_WME))))
4090 return 1;
4091 5331 return 0;
4092 }
4093
4094 196720 static void mysql_set_character_set_with_default_collation(MYSQL *mysql) {
4095 196720 const char *save = charsets_dir;
4096
2/2
✓ Branch 0 taken 66261 times.
✓ Branch 1 taken 130459 times.
196720 if (mysql->options.charset_dir) {
4097 #ifdef MYSQL_SERVER
4098 // Do not change charsets_dir, it is not thread safe.
4099 assert(false);
4100 #else
4101 66261 charsets_dir = mysql->options.charset_dir;
4102 #endif
4103 }
4104
2/2
✓ Branch 0 taken 196730 times.
✓ Branch 1 taken 2 times.
196720 if ((mysql->charset = get_charset_by_csname(mysql->options.charset_name,
4105 MY_CS_PRIMARY, MYF(MY_WME)))) {
4106 /* Try to set compiled default collation when it's possible. */
4107 CHARSET_INFO *collation;
4108 196728 if ((collation =
4109
4/4
✓ Branch 0 taken 196726 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 190474 times.
✓ Branch 3 taken 6254 times.
393451 get_charset_by_name(MYSQL_DEFAULT_COLLATION_NAME, MYF(MY_WME))) &&
4110
2/2
✓ Branch 0 taken 190475 times.
✓ Branch 1 taken 6246 times.
196726 my_charset_same(mysql->charset, collation)) {
4111 190474 mysql->charset = collation;
4112 } else {
4113 /*
4114 Default compiled collation not found, or is not applicable
4115 to the requested character set.
4116 Continue with the default collation of the character set.
4117 */
4118 }
4119 }
4120 196730 charsets_dir = save;
4121 196730 }
4122
4123 196720 int mysql_init_character_set(MYSQL *mysql) {
4124 /* Set character set */
4125
2/2
✓ Branch 0 taken 20849 times.
✓ Branch 1 taken 175871 times.
196720 if (!mysql->options.charset_name) {
4126 20854 if (!(mysql->options.charset_name =
4127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20854 times.
20849 my_strdup(key_memory_mysql_options, MYSQL_DEFAULT_CHARSET_NAME,
4128 MYF(MY_WME))))
4129 return 1;
4130 351742 } else if (!strcmp(mysql->options.charset_name,
4131
3/4
✓ Branch 0 taken 5331 times.
✓ Branch 1 taken 170540 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 175871 times.
181202 MYSQL_AUTODETECT_CHARSET_NAME) &&
4132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5331 times.
5331 mysql_autodetect_character_set(mysql))
4133 return 1;
4134
4135 196725 mysql_set_character_set_with_default_collation(mysql);
4136
4137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 196724 times.
196724 if (!mysql->charset) {
4138 if (mysql->options.charset_dir)
4139 set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
4140 ER_CLIENT(CR_CANT_READ_CHARSET),
4141 mysql->options.charset_name,
4142 mysql->options.charset_dir);
4143 else {
4144 char cs_dir_name[FN_REFLEN];
4145 get_charsets_dir(cs_dir_name);
4146 set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
4147 ER_CLIENT(CR_CANT_READ_CHARSET),
4148 mysql->options.charset_name, cs_dir_name);
4149 }
4150 return 1;
4151 }
4152 196724 return 0;
4153 }
4154
4155 /*********** client side authentication support **************************/
4156
4157 static int client_mpvio_write_packet(MYSQL_PLUGIN_VIO *, const uchar *, int);
4158 static net_async_status client_mpvio_write_packet_nonblocking(
4159 struct MYSQL_PLUGIN_VIO *, const uchar *, int, int *);
4160 static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
4161 static net_async_status native_password_auth_client_nonblocking(
4162 MYSQL_PLUGIN_VIO *vio, MYSQL *mysql, int *result);
4163 static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
4164
4165 static auth_plugin_t native_password_client_plugin = {
4166 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
4167 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
4168 native_password_plugin_name,
4169 MYSQL_CLIENT_PLUGIN_AUTHOR_ORACLE,
4170 "Native MySQL authentication",
4171 {1, 0, 0},
4172 "GPL",
4173 nullptr,
4174 nullptr,
4175 nullptr,
4176 nullptr,
4177 nullptr,
4178 native_password_auth_client,
4179 native_password_auth_client_nonblocking};
4180
4181 static auth_plugin_t clear_password_client_plugin = {
4182 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
4183 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
4184 "mysql_clear_password",
4185 MYSQL_CLIENT_PLUGIN_AUTHOR_ORACLE,
4186 "Clear password authentication plugin",
4187 {0, 1, 0},
4188 "GPL",
4189 nullptr,
4190 nullptr,
4191 nullptr,
4192 nullptr,
4193 nullptr,
4194 clear_password_auth_client,
4195 nullptr};
4196
4197 static auth_plugin_t sha256_password_client_plugin = {
4198 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
4199 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
4200 "sha256_password",
4201 MYSQL_CLIENT_PLUGIN_AUTHOR_ORACLE,
4202 "SHA256 based authentication with salt",
4203 {1, 0, 0},
4204 "GPL",
4205 nullptr,
4206 sha256_password_init,
4207 sha256_password_deinit,
4208 nullptr,
4209 nullptr,
4210 sha256_password_auth_client,
4211 sha256_password_auth_client_nonblocking};
4212
4213 static auth_plugin_t caching_sha2_password_client_plugin = {
4214 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
4215 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
4216 caching_sha2_password_plugin_name,
4217 MYSQL_CLIENT_PLUGIN_AUTHOR_ORACLE,
4218 "SHA2 based authentication with salt",
4219 {1, 0, 0},
4220 "GPL",
4221 nullptr,
4222 caching_sha2_password_init,
4223 caching_sha2_password_deinit,
4224 nullptr,
4225 nullptr,
4226 caching_sha2_password_auth_client,
4227 caching_sha2_password_auth_client_nonblocking};
4228 #ifdef AUTHENTICATION_WIN
4229 extern "C" auth_plugin_t win_auth_client_plugin;
4230 #endif
4231
4232 /*
4233 Test trace plugin can be used only in debug builds. In non-debug ones
4234 it is ignored, even if it was enabled by build options (TEST_TRACE_PLUGIN
4235 macro).
4236 */
4237
4238 #if defined(CLIENT_PROTOCOL_TRACING) && defined(TEST_TRACE_PLUGIN) && \
4239 !defined(NDEBUG)
4240 extern auth_plugin_t test_trace_plugin;
4241 #endif
4242
4243 struct st_mysql_client_plugin *mysql_client_builtins[] = {
4244 (struct st_mysql_client_plugin *)&native_password_client_plugin,
4245 (struct st_mysql_client_plugin *)&clear_password_client_plugin,
4246 (struct st_mysql_client_plugin *)&sha256_password_client_plugin,
4247 (struct st_mysql_client_plugin *)&caching_sha2_password_client_plugin,
4248 #ifdef AUTHENTICATION_WIN
4249 (struct st_mysql_client_plugin *)&win_auth_client_plugin,
4250 #endif
4251 #if defined(CLIENT_PROTOCOL_TRACING) && defined(TEST_TRACE_PLUGIN) && \
4252 !defined(NDEBUG)
4253 (struct st_mysql_client_plugin *)&test_trace_plugin,
4254 #endif
4255 nullptr};
4256
4257 2067139 static uchar *write_length_encoded_string3(uchar *buf, const char *string,
4258 size_t length) {
4259 2067139 buf = net_store_length(buf, length);
4260 2067148 memcpy(buf, string, length);
4261 2067148 buf += length;
4262 2067148 return buf;
4263 }
4264
4265 /*
4266 The main purpose of this is to hide C++ from st_mysql_options_extention.
4267 */
4268 struct My_hash {
4269 malloc_unordered_map<string, string> hash{key_memory_mysql_options};
4270 };
4271
4272 168494 uchar *send_client_connect_attrs(MYSQL *mysql, uchar *buf) {
4273 /* check if the server supports connection attributes */
4274
1/2
✓ Branch 0 taken 168495 times.
✗ Branch 1 not taken.
168494 if (mysql->server_capabilities & CLIENT_CONNECT_ATTRS) {
4275 /* Always store the length if the client supports it */
4276 168495 buf = net_store_length(
4277
1/2
✓ Branch 0 taken 168496 times.
✗ Branch 1 not taken.
168495 buf, mysql->options.extension
4278 168496 ? mysql->options.extension->connection_attributes_length
4279 : 0);
4280
4281 /* check if we have connection attributes */
4282
1/2
✓ Branch 0 taken 168500 times.
✗ Branch 1 not taken.
168498 if (mysql->options.extension &&
4283
2/2
✓ Branch 0 taken 168495 times.
✓ Branch 1 taken 5 times.
168500 mysql->options.extension->connection_attributes) {
4284 /* loop over and dump the connection attributes */
4285 168495 for (const auto &key_and_value :
4286
2/2
✓ Branch 0 taken 1033562 times.
✓ Branch 1 taken 168496 times.
1370592 mysql->options.extension->connection_attributes->hash) {
4287 1033579 const string &key = key_and_value.first;
4288 1033579 const string &value = key_and_value.second;
4289
4290 /* we can't have zero length keys */
4291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1033595 times.
1033579 assert(!key.empty());
4292
4293
1/2
✓ Branch 0 taken 1033592 times.
✗ Branch 1 not taken.
1033595 buf = write_length_encoded_string3(buf, key.data(), key.size());
4294
1/2
✓ Branch 0 taken 1033586 times.
✗ Branch 1 not taken.
1033592 buf = write_length_encoded_string3(buf, value.data(), value.size());
4295 }
4296 }
4297 }
4298 168498 return buf;
4299 }
4300
4301 8313697 static size_t get_length_store_length(size_t length) {
4302 /* as defined in net_store_length */
4303 #define MAX_VARIABLE_STRING_LENGTH 9
4304 uchar length_buffer[MAX_VARIABLE_STRING_LENGTH], *ptr;
4305
4306
1/2
✓ Branch 0 taken 8313884 times.
✗ Branch 1 not taken.
8313697 ptr = net_store_length(length_buffer, length);
4307
4308 8313884 return ptr - &length_buffer[0];
4309 }
4310
4311 /*
4312 Write 1-8 bytes of string length header information to dest depending on
4313 value of src_len, then copy src_len bytes from src to dest.
4314
4315 @param dest Destination buffer of size src_len+8
4316 @param dest_end One byte past the end of the dest buffer
4317 @param src Source buff of size src_len
4318 @param src_end One byte past the end of the src buffer
4319
4320 @return pointer dest+src_len+header size or NULL if
4321 */
4322
4323 166500 static char *write_length_encoded_string4(char *dest, char *dest_end,
4324 const uchar *src,
4325 const uchar *src_end) {
4326 166500 size_t src_len = (size_t)(src_end - src);
4327 166500 uchar *to = net_store_length((uchar *)dest, src_len);
4328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 166511 times.
166511 if ((char *)(to + src_len) >= dest_end) return nullptr;
4329 166511 memcpy(to, src, src_len);
4330 166511 return (char *)(to + src_len);
4331 }
4332
4333 /*
4334 Write 1 byte of string length header information to dest and
4335 copy src_len bytes from src to dest.
4336 */
4337 static char *write_string(char *dest, char *dest_end, const uchar *src,
4338 const uchar *src_end) {
4339 size_t src_len = (size_t)(src_end - src);
4340 uchar *to = nullptr;
4341 if (src_len >= 251) return nullptr;
4342 *dest = (uchar)src_len;
4343 to = (uchar *)dest + 1;
4344 if ((char *)(to + src_len) >= dest_end) return nullptr;
4345 memcpy(to, src, src_len);
4346 return (char *)(to + src_len);
4347 }
4348 /**
4349 Sends a @ref page_protocol_com_change_user
4350 with a caller provided payload
4351
4352 @retval 0 ok
4353 @retval 1 error
4354 */
4355 243 static int send_change_user_packet(MCPVIO_EXT *mpvio, const uchar *data,
4356 int data_len) {
4357 243 MYSQL *mysql = mpvio->mysql;
4358 char *buff, *end;
4359 243 int res = 1;
4360 243 size_t connect_attrs_len =
4361 486 (mysql->server_capabilities & CLIENT_CONNECT_ATTRS &&
4362
1/2
✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
243 mysql->options.extension)
4363
1/2
✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
486 ? mysql->options.extension->connection_attributes_length
4364 : 0;
4365
4366 buff = static_cast<char *>(
4367 243 my_alloca(USERNAME_LENGTH + data_len + 1 + NAME_LEN + 2 + NAME_LEN +
4368 connect_attrs_len + 9 /* for the length of the attrs */));
4369
4370 243 end = strmake(buff, mysql->user, USERNAME_LENGTH) + 1;
4371
4372
1/2
✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
243 if (!data_len)
4373 243 *end++ = 0;
4374 else {
4375 assert(data_len <= 255);
4376 if (data_len > 255) {
4377 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
4378 goto error;
4379 }
4380 *end++ = data_len;
4381 memcpy(end, data, data_len);
4382 end += data_len;
4383 }
4384
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 13 times.
243 end = strmake(end, mpvio->db ? mpvio->db : "", NAME_LEN) + 1;
4385
4386
1/2
✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
243 if (mysql->server_capabilities & CLIENT_PROTOCOL_41) {
4387 243 int2store((uchar *)end, (ushort)mysql->charset->number);
4388 243 end += 2;
4389 }
4390
4391
1/2
✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
243 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
4392 243 end = strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
4393
4394 243 end = (char *)send_client_connect_attrs(mysql, (uchar *)end);
4395
4396
1/2
✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
243 res = simple_command(mysql, COM_CHANGE_USER, (uchar *)buff,
4397 (ulong)(end - buff), 1);
4398
4399 243 error:
4400 243 return res;
4401 }
4402
4403 /* clang-format off */
4404 /**
4405 @page page_protocol_connection_phase_packets_protocol_ssl_request Protocol::SSLRequest:
4406
4407 SSL Connection Request Packet. It is like
4408 @ref page_protocol_connection_phase_packets_protocol_handshake_response but is
4409 truncated right before username field. If server supports ::CLIENT_SSL
4410 capability, client can send this packet to request a secure SSL connection.
4411 The ::CLIENT_SSL capability flag must be set inside the SSL Connection Request Packet.
4412
4413 <table>
4414 <caption>Payload</caption>
4415 <tr><th>Type</th><th>Name</th><th>Description</th></tr>
4416 <tr><td colspan="3">if capabilities @& ::CLIENT_PROTOCOL_41 {</td></tr>
4417 <tr><td>@ref a_protocol_type_int4 "int&lt;4&gt;"</td>
4418 <td>client_flag</td>
4419 <td>\ref group_cs_capabilities_flags</td></tr>
4420 <tr><td>@ref a_protocol_type_int4 "int&lt;4&gt;"</td>
4421 <td>max_packet_size</td>
4422 <td>maximum packet size</td></tr>
4423 <tr><td>@ref a_protocol_type_int1 "int&lt;1&gt;"</td>
4424 <td>character_set</td>
4425 <td>client charset \ref a_protocol_character_set, only the lower 8-bits</td></tr>
4426 <tr><td>@ref sect_protocol_basic_dt_string_fix "string[23]"</td>
4427 <td>filler</td>
4428 <td>filler to the size of the handhshake response packet. All 0s.</td></tr>
4429 <tr><td colspan="3">} else {</td></tr>
4430 <tr><td>@ref a_protocol_type_int2 "int&lt;2&gt;"</td>
4431 <td>client_flag</td>
4432 <td>\ref group_cs_capabilities_flags, only the lower 16 bits</td></tr>
4433 <tr><td>@ref a_protocol_type_int3 "int&lt;3&gt;"</td>
4434 <td>max_packet_size</td>
4435 <td>maximum packet size, 0xFFFFFF max</td></tr>
4436 <tr><td colspan="3">}</td></tr>
4437 </table>
4438
4439 @sa int2store(), int3store(), int4store(), mysql_fill_packet_header()
4440 */
4441 /* clang-format on */
4442 /**
4443 Fill in the beginning of the client reply packet.
4444
4445 Used to fill in the beginning of the client reply packet
4446 or the ssl request packet.
4447
4448 @param mysql The mysql handler to operate
4449 @param[out] buff The buffer to receive the packet
4450 @param buff_size The max size of the buffer. Used in debug only.
4451 @return one past to where the buffer is filled
4452
4453 @sa page_protocol_conn_packets_protocol_ssl_request
4454 send_client_reply_packet()
4455 */
4456 186906 static char *mysql_fill_packet_header(MYSQL *mysql, char *buff,
4457 size_t buff_size [[maybe_unused]]) {
4458 186906 NET *net = &mysql->net;
4459 char *end;
4460 186906 uchar *buff_p = (uchar *)buff;
4461 /*
4462 Always send CLIENT_LOCAL_FILES to the server.
4463 This needs to be done since the client can always decide to support
4464 local files even if this option is disabled by enabling the directory.
4465 But we can't turn it on in the client flag since it's used throughout the
4466 code base if the option is enabled or not.
4467 */
4468 186906 unsigned long client_flag = mysql->client_flag | CLIENT_LOCAL_FILES;
4469
4470
1/2
✓ Branch 0 taken 186911 times.
✗ Branch 1 not taken.
186906 if (client_flag & CLIENT_PROTOCOL_41) {
4471 /* 4.1 server and 4.1 client has a 32 byte option flag */
4472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 186911 times.
186911 assert(buff_size >= 32);
4473
4474 186911 int4store(buff_p, client_flag);
4475 186908 int4store(buff_p + 4, net->max_packet_size);
4476 186910 buff[8] = (char)mysql->charset->number;
4477 186910 memset(buff + 9, 0, 32 - 9);
4478 186910 end = buff + 32;
4479 } else {
4480 assert(buff_size >= 5);
4481 assert(client_flag <= UINT_MAX16);
4482
4483 int2store(buff_p, (uint16)client_flag);
4484 int3store(buff_p + 2, net->max_packet_size);
4485 5 end = buff + 5;
4486 }
4487 186915 return end;
4488 }
4489
4490 /**
4491 Calculates client capabilities in effect (mysql->client_flag)
4492
4493 Needs to be called immediately after receiving the server handshake packet.
4494
4495 @param mysql the connection context
4496 @param db The database specified by the client app
4497 @param client_flag The client flag as specified by the client app
4498 */
4499
4500 168412 static void cli_calculate_client_flag(MYSQL *mysql, const char *db,
4501 ulong client_flag) {
4502 168412 mysql->client_flag = client_flag;
4503 168412 mysql->client_flag |= mysql->options.client_flag;
4504 168412 mysql->client_flag |= CLIENT_CAPABILITIES;
4505
4506
2/2
✓ Branch 0 taken 145838 times.
✓ Branch 1 taken 22574 times.
168412 if (mysql->client_flag & CLIENT_MULTI_STATEMENTS)
4507 145838 mysql->client_flag |= CLIENT_MULTI_RESULTS;
4508
4509
1/2
✓ Branch 0 taken 168427 times.
✗ Branch 1 not taken.
168412 if (mysql->options.extension &&
4510
2/2
✓ Branch 0 taken 58699 times.
✓ Branch 1 taken 109728 times.
168427 mysql->options.extension->ssl_mode != SSL_MODE_DISABLED)
4511 58699 mysql->client_flag |= CLIENT_SSL;
4512
4513
2/2
✓ Branch 0 taken 89253 times.
✓ Branch 1 taken 79159 times.
168412 if (db)
4514 89253 mysql->client_flag |= CLIENT_CONNECT_WITH_DB;
4515 else
4516 79159 mysql->client_flag &= ~CLIENT_CONNECT_WITH_DB;
4517
4518 /* Remove options that server doesn't support */
4519 168412 mysql->client_flag = mysql->client_flag &
4520 (~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41 |
4521 168412 CLIENT_OPTIONAL_RESULTSET_METADATA) |
4522 168412 mysql->server_capabilities);
4523
4524
2/2
✓ Branch 0 taken 102091 times.
✓ Branch 1 taken 66321 times.
168412 if (mysql->options.protocol == MYSQL_PROTOCOL_SOCKET &&
4525
1/2
✓ Branch 0 taken 102091 times.
✗ Branch 1 not taken.
102091 mysql->options.extension &&
4526
2/2
✓ Branch 0 taken 97282 times.
✓ Branch 1 taken 4809 times.
102091 mysql->options.extension->ssl_mode <= SSL_MODE_PREFERRED) {
4527 97282 mysql->client_flag &= ~CLIENT_SSL;
4528 97282 mysql->options.extension->ssl_mode = SSL_MODE_DISABLED;
4529 }
4530 168412 }
4531
4532 32339 static SSL_SESSION *ssl_session_deserialize_from_data(MYSQL *mysql) {
4533 64676 return ssl_session_deserialize_from_data_ptr(
4534 mysql,
4535 32339 reinterpret_cast<char *>(mysql->options.extension->ssl_session_data));
4536 }
4537
4538 /**
4539 Establishes SSL if requested and supported.
4540
4541 @param mysql the connection handle
4542 @retval 0 success
4543 @retval 1 failure
4544 */
4545 168363 static int cli_establish_ssl(MYSQL *mysql) {
4546 168363 NET *net = &mysql->net;
4547
4548 /* Don't fallback on unencrypted connection if SSL required. */
4549
1/2
✓ Branch 0 taken 168366 times.
✗ Branch 1 not taken.
168363 if (mysql->options.extension &&
4550
2/2
✓ Branch 0 taken 5339 times.
✓ Branch 1 taken 163027 times.
168366 mysql->options.extension->ssl_mode >= SSL_MODE_REQUIRED &&
4551
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 5318 times.
5339 !(mysql->server_capabilities & CLIENT_SSL)) {
4552 21 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4553 ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4554 "SSL is required but the server doesn't "
4555 "support it");
4556 21 goto error;
4557 }
4558
4559 /*
4560 If the ssl_mode is VERIFY_CA or VERIFY_IDENTITY, make sure that the
4561 connection doesn't succeed without providing the CA certificate.
4562 */
4563
1/2
✓ Branch 0 taken 168353 times.
✗ Branch 1 not taken.
168342 if (mysql->options.extension &&
4564
2/2
✓ Branch 0 taken 371 times.
✓ Branch 1 taken 167982 times.
168353 mysql->options.extension->ssl_mode > SSL_MODE_REQUIRED &&
4565
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 369 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
371 !(mysql->options.ssl_ca || mysql->options.ssl_capath)) {
4566 2 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4567 ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4568 "CA certificate is required if ssl-mode "
4569 "is VERIFY_CA or VERIFY_IDENTITY");
4570 2 goto error;
4571 }
4572
4573 /*
4574 Attempt SSL connection if ssl_mode != SSL_MODE_DISABLED and the
4575 server supports SSL. Fallback on unencrypted connection otherwise.
4576 */
4577
1/2
✓ Branch 0 taken 168345 times.
✗ Branch 1 not taken.
168340 if (mysql->options.extension &&
4578
2/2
✓ Branch 0 taken 24124 times.
✓ Branch 1 taken 144221 times.
168345 mysql->options.extension->ssl_mode != SSL_MODE_DISABLED &&
4579
2/2
✓ Branch 0 taken 18631 times.
✓ Branch 1 taken 5493 times.
24124 (mysql->server_capabilities & CLIENT_SSL)) {
4580 /* Do the SSL layering. */
4581 18631 struct st_mysql_options *options = &mysql->options;
4582 struct st_VioSSLFd *ssl_fd;
4583 18631 enum enum_ssl_init_error ssl_init_error = SSL_INITERR_NOERROR;
4584 const char *cert_error;
4585 unsigned long ssl_error;
4586 char buff[33], *end;
4587 18631 const bool verify_identity =
4588 18631 mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT;
4589
4590 /* check if server supports compression else turn off client capability */
4591
2/2
✓ Branch 0 taken 499 times.
✓ Branch 1 taken 18132 times.
18631 if (!(mysql->server_capabilities & CLIENT_ZSTD_COMPRESSION_ALGORITHM))
4592 499 mysql->client_flag &= ~CLIENT_ZSTD_COMPRESSION_ALGORITHM;
4593
2/2
✓ Branch 0 taken 499 times.
✓ Branch 1 taken 18132 times.
18631 if (!(mysql->server_capabilities & CLIENT_COMPRESS))
4594 499 mysql->client_flag &= ~CLIENT_COMPRESS;
4595
4596 18631 end = mysql_fill_packet_header(mysql, buff, sizeof(buff));
4597
4598 /*
4599 Send mysql->client_flag, max_packet_size - unencrypted otherwise
4600 the server does not know we want to do SSL
4601 */
4602
2/8
✓ Branch 0 taken 16261 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 16261 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
16261 MYSQL_TRACE(SEND_SSL_REQUEST, mysql,
4603 ((size_t)(end - buff), (const unsigned char *)buff));
4604
3/6
✓ Branch 0 taken 18633 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18633 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18633 times.
37265 if (my_net_write(net, (uchar *)buff, (size_t)(end - buff)) ||
4605
2/4
✓ Branch 0 taken 18633 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18633 times.
18633 net_flush(net)) {
4606 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
4607 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
4608 "sending connection information to server",
4609 errno);
4610 83 goto error;
4611 }
4612
4613
2/10
✓ Branch 0 taken 16261 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16261 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
16261 MYSQL_TRACE_STAGE(mysql, SSL_NEGOTIATION);
4614
4615 /* Create the VioSSLConnectorFd - init SSL and load certs */
4616
4/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 18597 times.
✓ Branch 2 taken 47 times.
✓ Branch 3 taken 18576 times.
37256 if (!(ssl_fd = new_VioSSLConnectorFd(
4617 18633 options->ssl_key, options->ssl_cert, options->ssl_ca,
4618
1/2
✓ Branch 0 taken 18623 times.
✗ Branch 1 not taken.
18633 options->ssl_capath, options->ssl_cipher,
4619
1/2
✓ Branch 0 taken 18633 times.
✗ Branch 1 not taken.
18633 options->extension ? options->extension->tls_ciphersuites
4620 : nullptr,
4621 &ssl_init_error,
4622
1/2
✓ Branch 0 taken 18633 times.
✗ Branch 1 not taken.
18633 options->extension ? options->extension->ssl_crl : nullptr,
4623
1/2
✓ Branch 0 taken 18633 times.
✗ Branch 1 not taken.
18633 options->extension ? options->extension->ssl_crlpath : nullptr,
4624
1/2
✓ Branch 0 taken 18633 times.
✗ Branch 1 not taken.
18633 options->extension ? options->extension->ssl_ctx_flags : 0,
4625 verify_identity ? mysql->host : nullptr))) {
4626
2/4
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47 times.
✗ Branch 3 not taken.
47 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4627 ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4628 sslGetErrString(ssl_init_error));
4629 47 goto error;
4630 }
4631 18576 mysql->connector_fd = (unsigned char *)ssl_fd;
4632
1/2
✓ Branch 0 taken 18575 times.
✗ Branch 1 not taken.
18576 SSL_SESSION *ssl_session = ssl_session_deserialize_from_data(mysql);
4633
4634 /* Connect to the server */
4635
3/8
✓ Branch 0 taken 18577 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18580 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18580 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
18575 DBUG_PRINT("info", ("IO layer change in progress..."));
4636
2/8
✓ Branch 0 taken 16215 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 16215 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
16215 MYSQL_TRACE(SSL_CONNECT, mysql, ());
4637
3/4
✓ Branch 0 taken 18581 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 18545 times.
18580 if (sslconnect(ssl_fd, net->vio, (long)(mysql->options.connect_timeout),
4638 ssl_session, &ssl_error, nullptr)) {
4639 char buf[512];
4640
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 ERR_error_string_n(ssl_error, buf, 512);
4641 36 buf[511] = 0;
4642
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4643 ER_CLIENT(CR_SSL_CONNECTION_ERROR), buf);
4644
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
36 if (ssl_session != nullptr) SSL_SESSION_free(ssl_session);
4645 36 goto error;
4646 }
4647
3/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 18503 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
18545 if (ssl_session != nullptr) SSL_SESSION_free(ssl_session);
4648
3/8
✓ Branch 0 taken 18546 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18547 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18547 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
18545 DBUG_PRINT("info", ("IO layer change done!"));
4649
4650 /* Verify server cert */
4651
3/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 18524 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18546 times.
18568 if (verify_identity &&
4652
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 ssl_verify_server_cert(net->vio, mysql->host, &cert_error)) {
4653 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4654 ER_CLIENT(CR_SSL_CONNECTION_ERROR), cert_error);
4655 goto error;
4656 }
4657
4658
2/8
✓ Branch 0 taken 16199 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 16199 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
16199 MYSQL_TRACE(SSL_CONNECTED, mysql, ());
4659
2/10
✓ Branch 0 taken 16199 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16199 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
16199 MYSQL_TRACE_STAGE(mysql, AUTHENTICATE);
4660 }
4661
4662 168255 return 0;
4663
4664 106 error:
4665 106 return 1;
4666 }
4667
4668 /**
4669 This function will establish asynchronous ssl connection by completing 4
4670 different ssl connection states. Initial state is set to SSL_NONE during
4671 which this functions does priliminary checks like if server supports ssl
4672 or not, if CA certificate is required etc. Once preliminary checks are
4673 done state is changed to SSL_REQUEST. In this state ssl request packet
4674 is sent by client. If this network IO is complete, state is changed to
4675 SSL_CONNECT. During SSL_CONNECT sslconnect() is called which can return
4676 immediately or complete SSL handshake. If it returns immediately client
4677 will save all SSL context in struct mysql_async_auth, so that next call
4678 to this function will ensure that SSL_new() is not called twice. Once
4679 ssl connection is established state is changed to SSL_COMPLETE.
4680
4681 @param[in] mysql Client connection handle.
4682 @param[out] res set to false in case of success and true for
4683 error.
4684
4685 @retval NET_ASYNC_NOT_READY ssl connection not yet established
4686 @retval NET_ASYNC_COMPLETE ssl connection established
4687 */
4688 13780 static net_async_status cli_establish_ssl_nonblocking(MYSQL *mysql, int *res) {
4689
1/2
✓ Branch 0 taken 13780 times.
✗ Branch 1 not taken.
13780 DBUG_TRACE;
4690 13780 NET *net = &mysql->net;
4691
1/2
✓ Branch 0 taken 13780 times.
✗ Branch 1 not taken.
13780 NET_ASYNC *net_async = NET_ASYNC_DATA(net);
4692
2/6
✓ Branch 0 taken 13780 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13780 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
13780 mysql_async_connect *ctx = ASYNC_DATA(mysql)->connect_context;
4693
4694
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 13730 times.
13780 if (ctx->ssl_state == SSL_NONE) {
4695 /* Don't fallback on unencrypted connection if SSL required. */
4696
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if (mysql->options.extension &&
4697
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 17 times.
50 mysql->options.extension->ssl_mode >= SSL_MODE_REQUIRED &&
4698
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 !(mysql->server_capabilities & CLIENT_SSL)) {
4699 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4700 ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4701 "SSL is required but the server doesn't "
4702 "support it");
4703 goto error;
4704 }
4705
4706 /*
4707 If the ssl_mode is VERIFY_CA or VERIFY_IDENTITY, make sure
4708 that the connection doesn't succeed without providing the
4709 CA certificate.
4710 */
4711
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if (mysql->options.extension &&
4712
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 mysql->options.extension->ssl_mode > SSL_MODE_REQUIRED &&
4713 !(mysql->options.ssl_ca || mysql->options.ssl_capath)) {
4714 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4715 ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4716 "CA certificate is required if ssl-mode "
4717 "is VERIFY_CA or VERIFY_IDENTITY");
4718 goto error;
4719 }
4720
4721 /*
4722 Attempt SSL connection if ssl_mode != SSL_MODE_DISABLED and
4723 the server supports SSL. Fallback on unencrypted
4724 connection otherwise.
4725 */
4726
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if (!mysql->options.extension ||
4727
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 17 times.
50 mysql->options.extension->ssl_mode == SSL_MODE_DISABLED ||
4728
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 !(mysql->server_capabilities & CLIENT_SSL)) {
4729 17 goto done;
4730 }
4731 33 ctx->ssl_state = SSL_REQUEST;
4732 }
4733
4734
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 13730 times.
13763 if (ctx->ssl_state == SSL_REQUEST) {
4735 char buff[33], *end;
4736
4737 33 end = mysql_fill_packet_header(mysql, buff, sizeof(buff));
4738
4739 /*
4740 Send mysql->client_flag, max_packet_size - unencrypted
4741 otherwise the server does not know we want to do SSL
4742 */
4743
2/8
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
33 MYSQL_TRACE(SEND_SSL_REQUEST, mysql,
4744 ((size_t)(end - buff), (const unsigned char *)buff));
4745 bool ret;
4746
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (my_net_write_nonblocking(net, (uchar *)buff, (size_t)(end - buff),
4747
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 &ret) == NET_ASYNC_NOT_READY) {
4748 return NET_ASYNC_NOT_READY;
4749 }
4750
4751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (ret) {
4752 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
4753 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
4754 "sending connection information to server",
4755 errno);
4756 goto error;
4757 }
4758
4759 33 ctx->ssl_state = SSL_CONNECT;
4760 }
4761
4762
1/2
✓ Branch 0 taken 13763 times.
✗ Branch 1 not taken.
13763 if (ctx->ssl_state == SSL_CONNECT) {
4763 /* Do the SSL layering. */
4764 13763 struct st_mysql_options *options = &mysql->options;
4765 struct st_VioSSLFd *ssl_fd;
4766 enum enum_ssl_init_error ssl_init_error;
4767 const char *cert_error;
4768 unsigned long ssl_error;
4769 size_t ret;
4770 13763 const bool verify_identity =
4771 13763 mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT;
4772
4773
2/10
✓ Branch 0 taken 13763 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13763 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
13763 MYSQL_TRACE_STAGE(mysql, SSL_NEGOTIATION);
4774
4775
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 13730 times.
13763 if (!mysql->connector_fd) {
4776
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 long flags = options->extension ? options->extension->ssl_ctx_flags : 0;
4777
4778 /* Create the VioSSLConnectorFd - init SSL and load certs */
4779
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
66 if (!(ssl_fd = new_VioSSLConnectorFd(
4780 33 options->ssl_key, options->ssl_cert, options->ssl_ca,
4781
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 options->ssl_capath, options->ssl_cipher,
4782
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 options->extension ? options->extension->tls_ciphersuites
4783 : nullptr,
4784 &ssl_init_error,
4785
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 options->extension ? options->extension->ssl_crl : nullptr,
4786
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 options->extension ? options->extension->ssl_crlpath : nullptr,
4787 flags, verify_identity ? mysql->host : nullptr))) {
4788 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR,
4789 unknown_sqlstate,
4790 ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4791 sslGetErrString(ssl_init_error));
4792 goto error;
4793 }
4794 33 mysql->connector_fd = (unsigned char *)ssl_fd;
4795 } else {
4796 13730 ssl_fd = (struct st_VioSSLFd *)mysql->connector_fd;
4797 }
4798
1/2
✓ Branch 0 taken 13763 times.
✗ Branch 1 not taken.
13763 SSL_SESSION *ssl_session = ssl_session_deserialize_from_data(mysql);
4799
4800 /* Connect to the server */
4801
3/8
✓ Branch 0 taken 13763 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13763 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13763 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
13763 DBUG_PRINT("info", ("IO layer change in progress..."));
4802
2/8
✓ Branch 0 taken 13763 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13763 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
13763 MYSQL_TRACE(SSL_CONNECT, mysql, ());
4803
2/2
✓ Branch 0 taken 13731 times.
✓ Branch 1 taken 32 times.
13763 if ((ret = sslconnect(ssl_fd, net->vio,
4804
1/2
✓ Branch 0 taken 13763 times.
✗ Branch 1 not taken.
13763 (long)(mysql->options.connect_timeout), ssl_session,
4805 &ssl_error, &ctx->ssl))) {
4806
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 13731 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
13731 if (ssl_session != nullptr) SSL_SESSION_free(ssl_session);
4807
1/3
✓ Branch 0 taken 13731 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
13731 switch (ret) {
4808 13731 case VIO_SOCKET_WANT_READ:
4809 13731 net_async->async_blocking_state = NET_NONBLOCKING_READ;
4810 13731 return NET_ASYNC_NOT_READY;
4811 case VIO_SOCKET_WANT_WRITE:
4812 net_async->async_blocking_state = NET_NONBLOCKING_WRITE;
4813 return NET_ASYNC_NOT_READY;
4814 default:
4815 break;
4816 /* continue for error handling */
4817 }
4818
4819 char buf[512];
4820 ERR_error_string_n(ssl_error, buf, 512);
4821 buf[511] = 0;
4822 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4823 ER_CLIENT(CR_SSL_CONNECTION_ERROR), buf);
4824 goto error;
4825 }
4826
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
32 if (ssl_session != nullptr) SSL_SESSION_free(ssl_session);
4827
3/8
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
32 DBUG_PRINT("info", ("IO layer change done!"));
4828
4829 /* sslconnect creates a new vio, so update it. */
4830
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 vio_set_blocking_flag(net->vio, !ctx->non_blocking);
4831
4832 /* Verify server cert */
4833
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
32 if (verify_identity &&
4834 ssl_verify_server_cert(net->vio, mysql->host, &cert_error)) {
4835 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4836 ER_CLIENT(CR_SSL_CONNECTION_ERROR), cert_error);
4837 goto error;
4838 }
4839
4840
2/8
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
32 MYSQL_TRACE(SSL_CONNECTED, mysql, ());
4841
2/10
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
32 MYSQL_TRACE_STAGE(mysql, AUTHENTICATE);
4842 }
4843
4844 done:
4845 49 *res = 0;
4846 49 ctx->ssl_state = SSL_COMPLETE;
4847 49 return NET_ASYNC_COMPLETE;
4848
4849 error:
4850 *res = 1;
4851 ctx->ssl_state = SSL_COMPLETE;
4852 return NET_ASYNC_COMPLETE;
4853 13780 }
4854
4855 /**
4856 Asynchronous authentication phase is divided into several smaller chunks
4857 of subtasks like:
4858 1. Determine the default/initial plugin to use
4859 2. Call authentication plugin API
4860 3. Handle response from authentication plugin API
4861 4. Check if server asked to use a different authentication plugin
4862 5. In case server asked to use a different authentication plugin
4863 use that plugin to start the authentication process again.
4864 6. Complete authentication.
4865
4866 All above tasks are implemented in below authsm_* functions where
4867 authsm stads for authentication state machine.
4868 */
4869 static mysql_state_machine_status authsm_begin_plugin_auth(
4870 mysql_async_auth *ctx);
4871 static mysql_state_machine_status authsm_run_first_authenticate_user(
4872 mysql_async_auth *ctx);
4873 static mysql_state_machine_status authsm_handle_first_authenticate_user(
4874 mysql_async_auth *ctx);
4875 static mysql_state_machine_status authsm_read_change_user_result(
4876 mysql_async_auth *ctx);
4877 static mysql_state_machine_status authsm_handle_change_user_result(
4878 mysql_async_auth *ctx);
4879 static mysql_state_machine_status authsm_run_second_authenticate_user(
4880 mysql_async_auth *ctx);
4881 static mysql_state_machine_status authsm_handle_second_authenticate_user(
4882 mysql_async_auth *ctx);
4883 static mysql_state_machine_status authsm_finish_auth(mysql_async_auth *ctx);
4884 static mysql_state_machine_status authsm_init_multi_auth(mysql_async_auth *ctx);
4885 static mysql_state_machine_status authsm_do_multi_plugin_auth(
4886 mysql_async_auth *ctx);
4887 static mysql_state_machine_status authsm_handle_multi_auth_response(
4888 mysql_async_auth *ctx);
4889
4890 /**
4891 Asynchronous connection phase is divided into several smaller modules
4892 where wach module does following:
4893 1. Begin the connection to the server, including any DNS resolution
4894 necessary, socket configuration, etc
4895 2. Complete the connection itself
4896 3. Connection established, read the first packet
4897 4. Parse the handshake from the server
4898 5. Establish SSL connection if needed
4899 6. Invoke the plugin to send the authentication data to the server
4900 7. Authenticated, set initial database if specified
4901 8. Send COM_INIT_DB.
4902 9. Prepare to send a sequence of init commands.
4903 10.Send an init command.
4904
4905 Below are the modules which does all above tasks.
4906 */
4907 static mysql_state_machine_status csm_begin_connect(mysql_async_connect *ctx);
4908 static mysql_state_machine_status csm_complete_connect(
4909 mysql_async_connect *ctx);
4910 static mysql_state_machine_status csm_wait_connect(mysql_async_connect *ctx);
4911 static mysql_state_machine_status csm_read_greeting(mysql_async_connect *ctx);
4912 static mysql_state_machine_status csm_parse_handshake(mysql_async_connect *ctx);
4913 static mysql_state_machine_status csm_establish_ssl(mysql_async_connect *ctx);
4914 static mysql_state_machine_status csm_authenticate(mysql_async_connect *ctx);
4915 static mysql_state_machine_status csm_prep_select_database(
4916 mysql_async_connect *ctx);
4917 #ifndef MYSQL_SERVER
4918 static mysql_state_machine_status csm_prep_init_commands(
4919 mysql_async_connect *ctx);
4920 static mysql_state_machine_status csm_send_one_init_command(
4921 mysql_async_connect *ctx);
4922 #endif
4923
4924 #define MAX_CONNECTION_ATTR_STORAGE_LENGTH 65536
4925
4926 29838881 int mysql_get_socket_descriptor(MYSQL *mysql) {
4927
2/4
✓ Branch 0 taken 29838881 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29838881 times.
✗ Branch 3 not taken.
29838881 if (mysql && mysql->net.vio) {
4928 29838881 return vio_fd(mysql->net.vio);
4929 }
4930 return -1;
4931 }
4932
4933 /* clang-format off */
4934 /**
4935 @page page_protocol_connection_phase_packets_protocol_handshake_response Protocol::HandshakeResponse:
4936
4937 Depending on the servers support for the ::CLIENT_PROTOCOL_41 capability and
4938 the clients understanding of that flag the client has to send either
4939 a @ref sect_protocol_connection_phase_packets_protocol_handshake_response320 or
4940 @ref sect_protocol_connection_phase_packets_protocol_handshake_response41.
4941
4942 @sa send_client_reply_packet
4943
4944 @section sect_protocol_connection_phase_packets_protocol_handshake_response320 Protocol::HandshakeResponse320
4945
4946 Old Handshake Response Packet used by old clients or if the server doesn't
4947 support ::CLIENT_PROTOCOL_41 @ref group_cs_capabilities_flags flag.
4948
4949 <table>
4950 <caption>Payload</caption>
4951 <tr><th>Type</th><th>Name</th><th>Description</th></tr>
4952 <tr><td>@ref a_protocol_type_int2 "int&lt;2&gt;"</td>
4953 <td>client_flag</td>
4954 <td>\ref group_cs_capabilities_flags, only the lower 16 bits. ::CLIENT_PROTOCOL_41 should never be set</td></tr>
4955 <tr><td>@ref a_protocol_type_int3 "int&lt;3&gt;"</td>
4956 <td>max_packet_size</td>
4957 <td>maximum packet size, 0xFFFFFF max</td></tr>
4958 <tr><td>@ref sect_protocol_basic_dt_string_null "string&lt;NUL&gt;"</td>
4959 <td>username</td>
4960 <td>login user name</td></tr>
4961 <tr><td colspan="3">if capabilities @& ::CLIENT_CONNECT_WITH_DB {</td></tr>
4962 <tr><td>@ref sect_protocol_basic_dt_string_null "string&lt;NUL&gt;"</td>
4963 <td>auth-response</td>
4964 <td>Opaque authentication response data generated by
4965 Authentication Method indicated by the plugin name field.</td></tr>
4966 <tr><td>@ref sect_protocol_basic_dt_string_null "string&lt;NUL&gt;"</td>
4967 <td>database</td>
4968 <td>initial database for the connection.
4969 This string should be interpreted using the character set indicated by
4970 character set field.</td></tr>
4971 <tr><td colspan="3">} else {</td></tr>
4972 <tr><td>@ref sect_protocol_basic_dt_string_eof "string&lt;EOF&gt;"</td>
4973 <td>auth-response</td>
4974 <td>Opaque authentication response data generated by
4975 Authentication Method indicated by the plugin name field.</td></tr>
4976 <tr><td colspan="3">}</td></tr>
4977 </table>
4978
4979 Example
4980 ========
4981
4982 ~~~~~~~~~~~~~~~~~~~~~
4983 11 00 00 01 85 24 00 00 00 6f 6c 64 00 47 44 53 .....$...old.GDS
4984 43 51 59 52 5f CQYR_
4985 ~~~~~~~~~~~~~~~~~~~~~
4986
4987 @note If auth-response is followed by a database field it must be
4988 NULL terminated.
4989
4990 @section sect_protocol_connection_phase_packets_protocol_handshake_response41 Protocol::HandshakeResponse41
4991
4992 Handshake Response Packet sent by 4.1+ clients supporting
4993 ::CLIENT_PROTOCOL_41 @ref group_cs_capabilities_flags flag,
4994 if the server announced it in its
4995 @ref page_protocol_connection_phase_packets_protocol_handshake.
4996 Otherwise (talking to an old server) the
4997 @ref sect_protocol_connection_phase_packets_protocol_handshake_response320
4998 packet must be used.
4999
5000
5001 <table>
5002 <caption>Payload</caption>
5003 <tr><th>Type</th><th>Name</th><th>Description</th></tr>
5004 <tr><td>@ref a_protocol_type_int4 "int&lt;4&gt;"</td>
5005 <td>client_flag</td>
5006 <td>\ref group_cs_capabilities_flags, ::CLIENT_PROTOCOL_41 always set.</td></tr>
5007 <tr><td>@ref a_protocol_type_int4 "int&lt;4&gt;"</td>
5008 <td>max_packet_size</td>
5009 <td>maximum packet size</td></tr>
5010 <tr><td>@ref a_protocol_type_int1 "int&lt;1&gt;"</td>
5011 <td>character_set</td>
5012 <td>client charset \ref a_protocol_character_set, only the lower 8-bits</td></tr>
5013 <tr><td>@ref sect_protocol_basic_dt_string_fix "string[23]"</td>
5014 <td>filler</td>
5015 <td>filler to the size of the handhshake response packet. All 0s.</td></tr>
5016 <tr><td>@ref sect_protocol_basic_dt_string_null "string&lt;NUL&gt;"</td>
5017 <td>username</td>
5018 <td>login user name</td></tr>
5019 <tr><td colspan="3">if capabilities @& ::CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA {</td></tr>
5020 <tr><td>@ref sect_protocol_basic_dt_string_le "string&lt;length&gt;"</td>
5021 <td>auth_response</td>
5022 <td>opaque authentication response data generated by
5023 Authentication Method indicated by the plugin name field. </td></tr>
5024 <tr><td colspan="3">} else {</td></tr>
5025 <tr><td>@ref a_protocol_type_int1 "int&lt;1&gt;"</td>
5026 <td>auth_response_length</td>
5027 <td>length of auth_response</td></tr>
5028 <tr><td>@ref sect_protocol_basic_dt_string_le "string&lt;length&gt;"</td>
5029 <td>auth_response</td>
5030 <td>opaque authentication response data generated by
5031 Authentication Method indicated by the plugin name field. </td></tr>
5032 <tr><td colspan="3">}</td></tr>
5033 <tr><td colspan="3">if capabilities @& ::CLIENT_CONNECT_WITH_DB {</td></tr>
5034 <tr><td>@ref sect_protocol_basic_dt_string_null "string&lt;NUL&gt;"</td>
5035 <td>database</td>
5036 <td>initial database for the connection.
5037 This string should be interpreted using the character set indicated by
5038 character set field.</td></tr>
5039 <tr><td colspan="3">}</td></tr>
5040 <tr><td colspan="3">if capabilities @& ::CLIENT_PLUGIN_AUTH {</td></tr>
5041 <tr><td>@ref sect_protocol_basic_dt_string_null "string&lt;NUL&gt;"</td>
5042 <td>client_plugin_name</td>
5043 <td>the Authentication Method used by the client to generate
5044 auth-response value in this packet. This is an UTF-8 string. </td></tr>
5045 <tr><td colspan="3">}</td></tr>
5046 <tr><td colspan="3">if capabilities @& ::CLIENT_CONNECT_ATTRS {</td></tr>
5047 <tr><td>@ref sect_protocol_basic_dt_int_le "int&lt;lenenc&gt;"</td>
5048 <td>length of all key-values</td>
5049 <td>affected rows</td></tr>
5050 <tr><td>@ref sect_protocol_basic_dt_string_le "string&lt;lenenc&gt;"</td>
5051 <td>key1</td>
5052 <td>Name of the 1st client attribute</td></tr>
5053 <tr><td>@ref sect_protocol_basic_dt_string_le "string&lt;lenenc&gt;"</td>
5054 <td>value1</td>
5055 <td>Value of the 1st client attribute</td></tr>
5056 <tr><td colspan="3">.. (if more data in length of all key-values, more keys and values parts)</td></tr>
5057 <tr><td colspan="3">}</td></tr>
5058 <tr><td>@ref a_protocol_type_int1 "int&lt;1&gt;"</td>
5059 <td>zstd_compression_level</td>
5060 <td>compression level for zstd compression algorithm</td></tr>
5061 </table>
5062
5063 Example
5064 ========
5065
5066 On MySQL 5.5.8 with ::CLIENT_PROTOCOL_41 ::CLIENT_PLUGIN_AUTH, CLIENT_SECURE_CONNECTION (removed in 8.0),
5067 and ::CLIENT_CONNECT_WITH_DB set, it may look like:
5068
5069 ~~~~~~~~~~~~~~~~~~~~~
5070 54 00 00 01 8d a6 0f 00 00 00 00 01 08 00 00 00 T...............
5071 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5072 00 00 00 00 70 61 6d 00 14 ab 09 ee f6 bc b1 32 ....pam........2
5073 3e 61 14 38 65 c0 99 1d 95 7d 75 d4 47 74 65 73 >a.8e....}u.Gtes
5074 74 00 6d 79 73 71 6c 5f 6e 61 74 69 76 65 5f 70 t.mysql_native_p
5075 61 73 73 77 6f 72 64 00 assword.
5076 ~~~~~~~~~~~~~~~~~~~~~
5077
5078 Starting with MySQL 5.6.6 the client may send attributes
5079 if ::CLIENT_CONNECT_ATTRS is set:
5080
5081 ~~~~~~~~~~~~~~~~~~~~~
5082 b2 00 00 01 85 a2 1e 00 00 00 00 40 08 00 00 00 ...........@....
5083 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5084 00 00 00 00 72 6f 6f 74 00 14 22 50 79 a2 12 d4 ....root.."Py...
5085 e8 82 e5 b3 f4 1a 97 75 6b c8 be db 9f 80 6d 79 .......uk.....my
5086 73 71 6c 5f 6e 61 74 69 76 65 5f 70 61 73 73 77 sql_native_passw
5087 6f 72 64 00 61 03 5f 6f 73 09 64 65 62 69 61 6e ord.a._os.debian
5088 36 2e 30 0c 5f 63 6c 69 65 6e 74 5f 6e 61 6d 65 6.0._client_name
5089 08 6c 69 62 6d 79 73 71 6c 04 5f 70 69 64 05 32 .libmysql._pid.2
5090 32 33 34 34 0f 5f 63 6c 69 65 6e 74 5f 76 65 72 2344._client_ver
5091 73 69 6f 6e 08 35 2e 36 2e 36 2d 6d 39 09 5f 70 sion.5.6.6-m9._p
5092 6c 61 74 66 6f 72 6d 06 78 38 36 5f 36 34 03 66 latform.x86_64.f
5093 6f 6f 03 62 61 72 oo.bar
5094 ~~~~~~~~~~~~~~~~~~~~~
5095
5096 @warning Currently, multibyte character sets such as UCS2, UTF16 and
5097 UTF32 are not supported.
5098
5099 @note If client wants to have a secure SSL connection and sets
5100 CLIENT_SSL flag it should first send the
5101 @ref page_protocol_connection_phase_packets_protocol_ssl_request packet
5102 and only then, after establishing the secure connection, it should send
5103 the @ref page_protocol_connection_phase_packets_protocol_handshake_response
5104 packet.
5105 */
5106 /* clang-format on */
5107
5108 /**
5109 sends a client authentication packet (second packet in the 3-way handshake)
5110
5111 @param mpvio The connection to use
5112 @param data The scramble to send
5113 @param data_len Length of data
5114 @param buff_out Buffer holding client handshake packet
5115 @param buff_len Length of buffer holding client handshake packet
5116 @retval 0 ok
5117 @retval 1 error
5118
5119 @sa mysql_fill_packet_header()
5120 page_protocol_conn_packets_protocol_handshake_response
5121 */
5122 168297 static bool prep_client_reply_packet(MCPVIO_EXT *mpvio, const uchar *data,
5123 int data_len, char **buff_out,
5124 int *buff_len) {
5125
1/2
✓ Branch 0 taken 168319 times.
✗ Branch 1 not taken.
168297 DBUG_TRACE;
5126 168319 MYSQL *mysql = mpvio->mysql;
5127 // Simulate mismatching ssl_charset_code number in handshake response
5128 // In order to have different, but valid number using my_charset_* objects
5129
4/6
✓ Branch 0 taken 168319 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 168318 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
168319 DBUG_EXECUTE_IF("simulate_bad_ssl_charset_code", {
5130 if (mysql->charset->number != my_charset_bin.number)
5131 mysql->charset->number = my_charset_bin.number;
5132 else
5133 mysql->charset->number = my_charset_latin1.number;
5134 });
5135 char *buff, *end;
5136 size_t buff_size;
5137 168319 size_t connect_attrs_len =
5138 336639 (mysql->server_capabilities & CLIENT_CONNECT_ATTRS &&
5139
1/2
✓ Branch 0 taken 168321 times.
✗ Branch 1 not taken.
168320 mysql->options.extension)
5140
1/2
✓ Branch 0 taken 168320 times.
✗ Branch 1 not taken.
336639 ? mysql->options.extension->connection_attributes_length
5141 : 0;
5142 168319 unsigned int compress_level = 0;
5143 168319 bool server_zstd =
5144 168319 (mysql->server_capabilities & CLIENT_ZSTD_COMPRESSION_ALGORITHM);
5145 168319 bool client_zstd =
5146 168319 (mysql->options.client_flag & CLIENT_ZSTD_COMPRESSION_ALGORITHM);
5147
5148 /* validate compression configuration */
5149
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 168319 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
168319 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
5150
2/2
✓ Branch 0 taken 7878 times.
✓ Branch 1 taken 160441 times.
168319 if (mysql->options.extension->compression_algorithm) {
5151
1/2
✓ Branch 0 taken 7878 times.
✗ Branch 1 not taken.
7878 std::string algorithm = mysql->options.extension->compression_algorithm;
5152
1/2
✓ Branch 0 taken 7878 times.
✗ Branch 1 not taken.
15756 if (!algorithm.empty() &&
5153
8/16
✓ Branch 0 taken 7878 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7878 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 7876 times.
✓ Branch 6 taken 7878 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7878 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 7876 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
15756 validate_compression_attributes(algorithm, std::string(), true)) {
5154
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 set_mysql_error(mysql, CR_COMPRESSION_WRONGLY_CONFIGURED,
5155 unknown_sqlstate);
5156 2 return true;
5157 }
5158
2/2
✓ Branch 0 taken 7876 times.
✓ Branch 1 taken 2 times.
7878 }
5159
5160 /**
5161 If server/client is configured to use zstd compression then set compression
5162 level if specified, else set level to a default value.
5163 */
5164
4/4
✓ Branch 0 taken 162169 times.
✓ Branch 1 taken 6148 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 162061 times.
168317 if (server_zstd && client_zstd) {
5165
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 if (mysql->options.extension &&
5166
2/2
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 3 times.
108 mysql->options.extension->zstd_compression_level)
5167 105 compress_level = mysql->options.extension->zstd_compression_level;
5168 else
5169 3 compress_level = default_zstd_compression_level;
5170 }
5171 /* Remove those compression capabilities that server does not support. */
5172
2/2
✓ Branch 0 taken 6140 times.
✓ Branch 1 taken 162177 times.
168317 if (!(mysql->server_capabilities & CLIENT_COMPRESS))
5173 6140 mysql->client_flag &= ~CLIENT_COMPRESS;
5174
2/2
✓ Branch 0 taken 6124 times.
✓ Branch 1 taken 162193 times.
168317 if (!(mysql->server_capabilities & CLIENT_ZSTD_COMPRESSION_ALGORITHM))
5175 6124 mysql->client_flag &= ~CLIENT_ZSTD_COMPRESSION_ALGORITHM;
5176 /*
5177 If server and client have no compression algorithms in common, we must
5178 fall back to uncompressed. In that case, check that uncompressed is
5179 allowed by client.
5180 */
5181
2/2
✓ Branch 0 taken 168180 times.
✓ Branch 1 taken 137 times.
168317 if (!(mysql->client_flag & CLIENT_COMPRESS) &&
5182
2/2
✓ Branch 0 taken 168095 times.
✓ Branch 1 taken 85 times.
168180 !(mysql->client_flag & CLIENT_ZSTD_COMPRESSION_ALGORITHM) &&
5183
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 168035 times.
168095 mysql->options.extension->connection_compressed) {
5184
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 set_mysql_error(mysql, CR_COMPRESSION_WRONGLY_CONFIGURED, unknown_sqlstate);
5185 60 return true;
5186 }
5187
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 168257 times.
168257 assert(connect_attrs_len < MAX_CONNECTION_ATTR_STORAGE_LENGTH);
5188
5189 168257 *buff_out = nullptr;
5190 168257 *buff_len = 0;
5191
5192 /*
5193 Fixed size of the packet is 32 bytes. See mysql_fill_packet_header.
5194 +9 because data is a length encoded binary where meta data size is max 9.
5195 */
5196 336514 buff_size = 33 + USERNAME_LENGTH + data_len + 9 + NAME_LEN + NAME_LEN +
5197
4/4
✓ Branch 0 taken 162145 times.
✓ Branch 1 taken 6112 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 162037 times.
168257 connect_attrs_len + 9 + ((server_zstd && client_zstd) ? 1 : 0);
5198
5199 buff = static_cast<char *>(
5200
1/2
✓ Branch 0 taken 168254 times.
✗ Branch 1 not taken.
168257 my_malloc(PSI_NOT_INSTRUMENTED, buff_size, MYF(MY_WME | MY_ZEROFILL)));
5201
5202 /* The client_flags is already calculated. Just fill in the packet header */
5203 168254 end = mysql_fill_packet_header(mysql, buff, buff_size);
5204
5205
3/8
✓ Branch 0 taken 168255 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 168255 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 168255 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
168249 DBUG_PRINT(
5206 "info",
5207 ("Server version = '%s' capabilites: %lu status: %u client_flag: %lu",
5208 mysql->server_version, mysql->server_capabilities, mysql->server_status,
5209 mysql->client_flag));
5210
5211 static_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH, "");
5212
5213 /* This needs to be changed as it's not useful with big packets */
5214
2/2
✓ Branch 0 taken 168239 times.
✓ Branch 1 taken 14 times.
168253 if (mysql->user[0])
5215
1/2
✓ Branch 0 taken 168237 times.
✗ Branch 1 not taken.
168239 strmake(end, mysql->user, USERNAME_LENGTH);
5216 else {
5217 #if defined(KERBEROS_LIB_CONFIGURED)
5218 /*
5219 Kerberos user name should have already read inside LDAP SASL client
5220 plugin. If it is still empty we should return error.
5221 */
5222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (strcmp(mpvio->plugin->name, "authentication_ldap_sasl_client") == 0) {
5223 if (!mysql->user[0]) {
5224 set_mysql_error(mysql, CR_KERBEROS_USER_NOT_FOUND, unknown_sqlstate);
5225 return true;
5226 }
5227 } else
5228 #endif
5229
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 read_user_name(end);
5230 }
5231
5232 /* We have to handle different version of handshake here */
5233
3/8
✓ Branch 0 taken 168252 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 168251 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 168251 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
168251 DBUG_PRINT("info", ("user: %s", end));
5234 168251 end = strend(end) + 1;
5235
2/2
✓ Branch 0 taken 166524 times.
✓ Branch 1 taken 1731 times.
168255 if (data_len) {
5236 /*
5237 Since the older versions of server do not have
5238 CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA capability,
5239 a check is performed on this before sending auth data.
5240 If lenenc support is not available, the data is sent
5241 in the format of first byte representing the length of
5242 the string followed by the actual string.
5243 */
5244
1/2
✓ Branch 0 taken 166524 times.
✗ Branch 1 not taken.
166524 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA)
5245 166518 end = write_length_encoded_string4(end, (char *)(buff + buff_size), data,
5246
1/2
✓ Branch 0 taken 166518 times.
✗ Branch 1 not taken.
166524 data + data_len);
5247 else
5248 end =
5249 write_string(end, (char *)(buff + buff_size), data, data + data_len);
5250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 166518 times.
166518 if (end == nullptr) goto error;
5251 } else
5252 1731 *end++ = 0;
5253
5254 /* Add database if needed */
5255
3/4
✓ Branch 0 taken 89224 times.
✓ Branch 1 taken 79025 times.
✓ Branch 2 taken 89224 times.
✗ Branch 3 not taken.
168249 if (mpvio->db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB)) {
5256
1/2
✓ Branch 0 taken 89229 times.
✗ Branch 1 not taken.
89224 end = strmake(end, mpvio->db, NAME_LEN) + 1;
5257
1/2
✓ Branch 0 taken 89229 times.
✗ Branch 1 not taken.
89229 mysql->db = my_strdup(key_memory_MYSQL, mpvio->db, MYF(MY_WME));
5258 }
5259
5260
2/2
✓ Branch 0 taken 168252 times.
✓ Branch 1 taken 2 times.
168254 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
5261
1/2
✓ Branch 0 taken 168259 times.
✗ Branch 1 not taken.
168252 end = strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
5262
5263
1/2
✓ Branch 0 taken 168253 times.
✗ Branch 1 not taken.
168261 end = (char *)send_client_connect_attrs(mysql, (uchar *)end);
5264
5265
4/4
✓ Branch 0 taken 162162 times.
✓ Branch 1 taken 6091 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 162054 times.
168253 if (server_zstd && client_zstd) {
5266 /* send compression level if both client and server support it */
5267 108 *end = static_cast<unsigned char>(compress_level);
5268 108 end++;
5269 }
5270
5271 168253 *buff_out = buff;
5272 168253 *buff_len = end - buff;
5273
5274 168253 return false;
5275
5276 error:
5277 my_free(buff);
5278 return true;
5279 168315 }
5280
5281 168251 static int send_client_reply_packet(MCPVIO_EXT *mpvio, const uchar *data,
5282 int data_len) {
5283
1/2
✓ Branch 0 taken 168274 times.
✗ Branch 1 not taken.
168251 DBUG_TRACE;
5284 168274 MYSQL *mysql = mpvio->mysql;
5285 168274 NET *net = &mysql->net;
5286 168274 char *buff = nullptr, *end = nullptr;
5287 int buff_len;
5288 168274 int ret = 0;
5289 bool prep_err;
5290
5291
1/2
✓ Branch 0 taken 168276 times.
✗ Branch 1 not taken.
168274 prep_err = prep_client_reply_packet(mpvio, data, data_len, &buff, &buff_len);
5292
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 168214 times.
168276 if (prep_err) {
5293 62 return 1;
5294 }
5295
5296 168214 end = buff + buff_len;
5297 /* Write authentication package */
5298
2/8
✓ Branch 0 taken 157792 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 157792 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
157792 MYSQL_TRACE(SEND_AUTH_RESPONSE, mysql,
5299 ((size_t)(end - buff), (const unsigned char *)buff));
5300
4/6
✓ Branch 0 taken 168212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 168212 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 168211 times.
336426 if (my_net_write(net, (uchar *)buff, (size_t)(end - buff)) ||
5301
2/4
✓ Branch 0 taken 168212 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 168213 times.
168212 net_flush(net)) {
5302
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
5303 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
5304 1 "sending authentication information", errno);
5305 1 ret = 1;
5306 }
5307
3/8
✓ Branch 0 taken 157791 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 157790 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
157790 MYSQL_TRACE(PACKET_SENT, mysql, ((size_t)(end - buff)));
5308
1/2
✓ Branch 0 taken 168215 times.
✗ Branch 1 not taken.
168212 my_free(buff);
5309 168215 return ret;
5310 168277 }
5311
5312 46 static net_async_status send_client_reply_packet_nonblocking(MCPVIO_EXT *mpvio,
5313 const uchar *pkt,
5314 int pkt_len,
5315 bool *result) {
5316
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 DBUG_TRACE;
5317 46 MYSQL *mysql = mpvio->mysql;
5318
2/6
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
46 mysql_async_auth *ctx = ASYNC_DATA(mysql)->connect_context->auth_context;
5319 net_async_status status;
5320
5321 46 bool error = false;
5322
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (!ctx->change_user_buff) {
5323 46 error =
5324
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 prep_client_reply_packet(mpvio, pkt, pkt_len, &ctx->change_user_buff,
5325 &ctx->change_user_buff_len);
5326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (error) {
5327 goto end;
5328 }
5329 }
5330
5331 92 status = my_net_write_nonblocking(&mysql->net, (uchar *)ctx->change_user_buff,
5332
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 ctx->change_user_buff_len, &error);
5333
5334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (status == NET_ASYNC_NOT_READY) {
5335 return NET_ASYNC_NOT_READY;
5336 }
5337
5338 46 end:
5339 46 *result = error;
5340
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 my_free(ctx->change_user_buff);
5341 46 ctx->change_user_buff = nullptr;
5342
5343 46 return NET_ASYNC_COMPLETE;
5344 46 }
5345
5346 #ifdef __clang__
5347 // Clang UBSAN false positive?
5348 // Call to function through pointer to incorrect function type
5349 static int client_mpvio_read_packet(MYSQL_PLUGIN_VIO *mpv,
5350 uchar **buf) SUPPRESS_UBSAN;
5351 #endif // __clang__
5352
5353 /**
5354 vio->read_packet() callback method for client authentication plugins
5355
5356 This function is called by a client authentication plugin, when it wants
5357 to read data from the server.
5358 */
5359 186171 static int client_mpvio_read_packet(MYSQL_PLUGIN_VIO *mpv, uchar **buf) {
5360 186171 MCPVIO_EXT *mpvio = (MCPVIO_EXT *)mpv;
5361 186171 MYSQL *mysql = mpvio->mysql;
5362 ulong pkt_len;
5363
5364 /* there are cached data left, feed it to a plugin */
5365
2/2
✓ Branch 0 taken 171148 times.
✓ Branch 1 taken 15023 times.
186171 if (mpvio->cached_server_reply.pkt_received) {
5366 171148 *buf = mpvio->cached_server_reply.pkt;
5367 171148 mpvio->cached_server_reply.pkt = nullptr;
5368 171148 mpvio->packets_read++;
5369 171148 pkt_len = mpvio->cached_server_reply.pkt_len;
5370 171148 mpvio->cached_server_reply.pkt_len = 0;
5371 171148 mpvio->cached_server_reply.pkt_received = false;
5372 171148 return pkt_len;
5373 }
5374
5375
2/2
✓ Branch 0 taken 369 times.
✓ Branch 1 taken 14654 times.
15023 if (mpvio->packets_read == 0) {
5376 /*
5377 the server handshake packet came from the wrong plugin,
5378 or it's mysql_change_user(). Either way, there is no data
5379 for a plugin to read. send a dummy packet to the server
5380 to initiate a dialog.
5381 */
5382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 369 times.
369 if (client_mpvio_write_packet(mpv, nullptr, 0)) return (int)packet_error;
5383 }
5384
5385 /* otherwise read the data */
5386 15023 pkt_len = (*mysql->methods->read_change_user_result)(mysql);
5387
5388 /* error while reading the change user request */
5389
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 14988 times.
15030 if (pkt_len == packet_error) return (int)packet_error;
5390
5391 14988 mpvio->last_read_packet_len = pkt_len;
5392 14988 *buf = mysql->net.read_pos;
5393
5394 /* was it a request to change plugins ? */
5395
2/2
✓ Branch 0 taken 963 times.
✓ Branch 1 taken 14025 times.
14988 if (**buf == 254)
5396 963 return (int)packet_error; /* if yes, this plugin shan't continue */
5397
5398 /*
5399 the server sends \1\255 or \1\254 instead of just \255 or \254 -
5400 for us to not confuse it with an error or "change plugin" packets.
5401 We remove this escaping \1 here.
5402
5403 See also server_mpvio_write_packet() where the escaping is done.
5404 */
5405
2/4
✓ Branch 0 taken 14025 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14025 times.
✗ Branch 3 not taken.
14025 if (pkt_len && **buf == 1) {
5406 14025 (*buf)++;
5407 14025 pkt_len--;
5408 }
5409 14025 mpvio->packets_read++;
5410 14025 return pkt_len;
5411 }
5412
5413 /**
5414 vio->read_packet() nonblocking callback method for client authentication
5415 plugins
5416 */
5417 3642 static net_async_status client_mpvio_read_packet_nonblocking(
5418 struct MYSQL_PLUGIN_VIO *mpv, uchar **buf, int *result) {
5419
1/2
✓ Branch 0 taken 3642 times.
✗ Branch 1 not taken.
3642 DBUG_TRACE;
5420 3642 MCPVIO_EXT *mpvio = (MCPVIO_EXT *)mpv;
5421 3642 MYSQL *mysql = mpvio->mysql;
5422 ulong pkt_len;
5423 int error;
5424
5425 /* there are cached data left, feed it to a plugin */
5426
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 3593 times.
3642 if (mpvio->cached_server_reply.pkt_received) {
5427 49 *buf = mpvio->cached_server_reply.pkt;
5428 49 mpvio->cached_server_reply.pkt = nullptr;
5429 49 mpvio->packets_read++;
5430 49 *result = mpvio->cached_server_reply.pkt_len;
5431 49 mpvio->cached_server_reply.pkt_len = 0;
5432 49 mpvio->cached_server_reply.pkt_received = false;
5433 49 return NET_ASYNC_COMPLETE;
5434 }
5435
5436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3593 times.
3593 if (mpvio->packets_read == 0) {
5437 /*
5438 the server handshake packet came from the wrong plugin,
5439 or it's mysql_change_user(). Either way, there is no data
5440 for a plugin to read. send a dummy packet to the server
5441 to initiate a dialog.
5442 */
5443 net_async_status status =
5444 client_mpvio_write_packet_nonblocking(mpv, nullptr, 0, &error);
5445 if (status == NET_ASYNC_NOT_READY) {
5446 return NET_ASYNC_NOT_READY;
5447 }
5448 if (error) {
5449 *result = (int)packet_error;
5450 return NET_ASYNC_COMPLETE;
5451 }
5452 }
5453
5454 /*
5455 packets_read needs to be set here to avoid entering above condition
5456 again.
5457 */
5458 3593 mpvio->packets_read++;
5459 /* otherwise read the data */
5460 net_async_status status =
5461
1/2
✓ Branch 0 taken 3593 times.
✗ Branch 1 not taken.
3593 mysql->methods->read_change_user_result_nonblocking(mysql, &pkt_len);
5462
2/2
✓ Branch 0 taken 3570 times.
✓ Branch 1 taken 23 times.
3593 if (status == NET_ASYNC_NOT_READY) {
5463 3570 return NET_ASYNC_NOT_READY;
5464 }
5465
5466 23 mpvio->last_read_packet_len = pkt_len;
5467 23 *buf = mysql->net.read_pos;
5468
5469 /* was it a request to change plugins ? */
5470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (**buf == 254) {
5471 *result = (int)packet_error;
5472 return NET_ASYNC_COMPLETE;
5473 }
5474
5475 /*
5476 the server sends \1\255 or \1\254 instead of just \255 or \254 -
5477 for us to not confuse it with an error or "change plugin" packets.
5478 We remove this escaping \1 here.
5479 See also server_mpvio_write_packet() where the escaping is
5480 done.
5481 */
5482
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 if (pkt_len && **buf == 1) {
5483 23 (*buf)++;
5484 23 pkt_len--;
5485 }
5486 23 *result = pkt_len;
5487 23 return NET_ASYNC_COMPLETE;
5488 3642 }
5489
5490 #ifdef __clang__
5491 // Clang UBSAN false positive?
5492 // Call to function through pointer to incorrect function type
5493 static int client_mpvio_write_packet(MYSQL_PLUGIN_VIO *mpv, const uchar *pkt,
5494 int pkt_len) SUPPRESS_UBSAN;
5495 #endif // __clang__
5496
5497 /**
5498 vio->write_packet() callback method for client authentication plugins
5499
5500 This function is called by a client authentication plugin, when it wants
5501 to send data to the server.
5502
5503 It transparently wraps the data into a change user or authentication
5504 handshake packet, if necessary.
5505 */
5506 173331 static int client_mpvio_write_packet(MYSQL_PLUGIN_VIO *mpv, const uchar *pkt,
5507 int pkt_len) {
5508 int res;
5509 173331 MCPVIO_EXT *mpvio = (MCPVIO_EXT *)mpv;
5510
5511
2/2
✓ Branch 0 taken 168497 times.
✓ Branch 1 taken 4834 times.
173331 if (mpvio->packets_written == 0) {
5512
2/2
✓ Branch 0 taken 243 times.
✓ Branch 1 taken 168254 times.
168497 if (mpvio->mysql_change_user)
5513 243 res = send_change_user_packet(mpvio, pkt, pkt_len);
5514 else
5515 168254 res = send_client_reply_packet(mpvio, pkt, pkt_len);
5516 } else {
5517 4834 NET *net = &mpvio->mysql->net;
5518
5519
2/6
✓ Branch 0 taken 4468 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4468 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4465 MYSQL_TRACE(SEND_AUTH_DATA, mpvio->mysql, ((size_t)pkt_len, pkt));
5520
5521
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4837 times.
4837 if (mpvio->mysql->thd)
5522 res = 1; /* no chit-chat in embedded */
5523 else
5524
2/4
✓ Branch 0 taken 4838 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4838 times.
4837 res = my_net_write(net, pkt, pkt_len) || net_flush(net);
5525
5526
2/2
✓ Branch 0 taken 4468 times.
✓ Branch 1 taken 370 times.
4838 if (!res) {
5527
2/6
✓ Branch 0 taken 4468 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4468 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4468 MYSQL_TRACE(PACKET_SENT, mpvio->mysql, ((size_t)pkt_len));
5528 } else
5529 set_mysql_extended_error(mpvio->mysql, CR_SERVER_LOST, unknown_sqlstate,
5530 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
5531 "sending authentication information", errno);
5532 }
5533 173353 mpvio->packets_written++;
5534 173353 return res;
5535 }
5536
5537 /**
5538 vio->write_packet() nonblocking callback method for client authentication
5539 plugins
5540 */
5541 60 static net_async_status client_mpvio_write_packet_nonblocking(
5542 struct MYSQL_PLUGIN_VIO *mpv, const uchar *pkt, int pkt_len, int *result) {
5543
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 DBUG_TRACE;
5544 60 MCPVIO_EXT *mpvio = (MCPVIO_EXT *)mpv;
5545 60 bool error = false;
5546
5547
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 14 times.
60 if (mpvio->packets_written == 0) {
5548 /* mysql_change_user_nonblocking not implemented yet. */
5549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 assert(!mpvio->mysql_change_user);
5550 net_async_status status =
5551
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 send_client_reply_packet_nonblocking(mpvio, pkt, pkt_len, &error);
5552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (status == NET_ASYNC_NOT_READY) {
5553 return NET_ASYNC_NOT_READY;
5554 }
5555 } else {
5556 14 NET *net = &mpvio->mysql->net;
5557
5558
2/8
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
14 MYSQL_TRACE(SEND_AUTH_DATA, mpvio->mysql, ((size_t)pkt_len, pkt));
5559
5560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (mpvio->mysql->thd)
5561 *result = 1; /* no chit-chat in embedded */
5562 else {
5563 net_async_status status =
5564
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 my_net_write_nonblocking(net, pkt, pkt_len, &error);
5565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (status == NET_ASYNC_NOT_READY) {
5566 return NET_ASYNC_NOT_READY;
5567 }
5568 14 *result = error;
5569
5570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (error) {
5571 set_mysql_extended_error(mpvio->mysql, CR_SERVER_LOST, unknown_sqlstate,
5572 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
5573 "sending authentication information", errno);
5574 } else {
5575
2/8
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
14 MYSQL_TRACE(PACKET_SENT, mpvio->mysql, ((size_t)pkt_len));
5576 }
5577 }
5578 }
5579 60 mpvio->packets_written++;
5580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 *result = error ? -1 : 0;
5581 60 return NET_ASYNC_COMPLETE;
5582 60 }
5583
5584 /**
5585 fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
5586 connection
5587 */
5588 1 void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info) {
5589 1 memset(info, 0, sizeof(*info));
5590
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 switch (vio->type) {
5591 case VIO_TYPE_TCPIP:
5592 info->protocol = MYSQL_PLUGIN_VIO_INFO::MYSQL_VIO_TCP;
5593 info->socket = (int)vio_fd(vio);
5594 return;
5595 1 case VIO_TYPE_SOCKET:
5596 1 info->protocol = MYSQL_PLUGIN_VIO_INFO::MYSQL_VIO_SOCKET;
5597 1 info->socket = (int)vio_fd(vio);
5598 1 return;
5599 case VIO_TYPE_SSL: {
5600 struct sockaddr addr;
5601 socklen_t addrlen = sizeof(addr);
5602 if (getsockname(vio_fd(vio), &addr, &addrlen)) return;
5603 info->protocol = addr.sa_family == AF_UNIX
5604 ? MYSQL_PLUGIN_VIO_INFO::MYSQL_VIO_SOCKET
5605 : MYSQL_PLUGIN_VIO_INFO::MYSQL_VIO_TCP;
5606 info->socket = (int)vio_fd(vio);
5607 return;
5608 }
5609 #ifdef _WIN32
5610 case VIO_TYPE_NAMEDPIPE:
5611 info->protocol = MYSQL_PLUGIN_VIO_INFO::MYSQL_VIO_PIPE;
5612 info->handle = vio->hPipe;
5613 return;
5614 #if defined(_WIN32)
5615 case VIO_TYPE_SHARED_MEMORY:
5616 info->protocol = MYSQL_PLUGIN_VIO_INFO::MYSQL_VIO_MEMORY;
5617 info->handle = vio->handle_file_map; /* or what ? */
5618 return;
5619 #endif
5620 #endif
5621 default:
5622 assert(0);
5623 }
5624 }
5625
5626 static void client_mpvio_info(MYSQL_PLUGIN_VIO *vio,
5627 MYSQL_PLUGIN_VIO_INFO *info) {
5628 MCPVIO_EXT *mpvio = (MCPVIO_EXT *)vio;
5629 mpvio_info(mpvio->mysql->net.vio, info);
5630 }
5631
5632 bool libmysql_cleartext_plugin_enabled = false;
5633
5634 171579 static bool check_plugin_enabled(MYSQL *mysql, mysql_async_auth *ctx) {
5635
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 171563 times.
171579 if (ctx->auth_plugin == &clear_password_client_plugin &&
5636
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 (!libmysql_cleartext_plugin_enabled &&
5637
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 (!mysql->options.extension ||
5638
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
16 !mysql->options.extension->enable_cleartext_plugin))) {
5639 4 set_mysql_extended_error(
5640 mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, unknown_sqlstate,
5641 ER_CLIENT(CR_AUTH_PLUGIN_CANNOT_LOAD),
5642 clear_password_client_plugin.name, "plugin not enabled");
5643 4 return true;
5644 }
5645
3/4
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 171526 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 49 times.
171575 if (ctx->non_blocking && !ctx->auth_plugin->authenticate_user_nonblocking) {
5646 set_mysql_extended_error(
5647 mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, unknown_sqlstate,
5648 ER_CLIENT(CR_AUTH_PLUGIN_CANNOT_LOAD), ctx->auth_plugin->name,
5649 "plugin does not support nonblocking connect");
5650 /*
5651 We don't return true here because not all authentication plugins support
5652 non-blocking APIs.
5653 In case plugin does not have non-blocking API, we fallback to blocking
5654 API calls to further proceed with the authentication.
5655 */
5656 }
5657 171575 return false;
5658 }
5659
5660 /**
5661 Client side of the plugin driver authentication.
5662
5663 @note this is used by both the mysql_real_connect and mysql_change_user
5664
5665 @param mysql mysql
5666 @param data pointer to the plugin auth data (scramble) in the
5667 handshake packet
5668 @param data_len the length of the data
5669 @param data_plugin a plugin that data were prepared for
5670 or 0 if it's mysql_change_user()
5671 @param db initial db to use, can be 0
5672
5673 @retval 0 ok
5674 @retval 1 error
5675 */
5676 168501 int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
5677 const char *data_plugin, const char *db) {
5678
1/2
✓ Branch 0 taken 168516 times.
✗ Branch 1 not taken.
168501 DBUG_TRACE;
5679 mysql_state_machine_status status;
5680 mysql_async_auth ctx;
5681 168516 memset(&ctx, 0, sizeof(ctx));
5682
5683 168516 ctx.mysql = mysql;
5684 168516 ctx.data = data;
5685 168516 ctx.data_len = data_len;
5686 168516 ctx.data_plugin = data_plugin;
5687 168516 ctx.db = db;
5688 168516 ctx.non_blocking = false;
5689 /* set initial auth factor to be first factor */
5690 168516 ctx.current_factor_index = 0;
5691 168516 ctx.state_function = authsm_begin_plugin_auth;
5692
5693 do {
5694
1/2
✓ Branch 0 taken 1014981 times.
✗ Branch 1 not taken.
1014981 status = ctx.state_function(&ctx);
5695
3/8
✓ Branch 0 taken 1014984 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1014981 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1014981 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1014981 DBUG_PRINT("info", ("status %d", (int)status));
5696
4/4
✓ Branch 0 taken 1013229 times.
✓ Branch 1 taken 1752 times.
✓ Branch 2 taken 846465 times.
✓ Branch 3 taken 166764 times.
1014981 } while (status != STATE_MACHINE_FAILED && status != STATE_MACHINE_DONE);
5697
5698 168519 return status == STATE_MACHINE_FAILED;
5699 168516 }
5700
5701 /**
5702 This functions drives the authentication on client side in a nonblocking
5703 way. This function will call different modules in a sequence where each
5704 module is responsible to achieve a particular part in entire authentication
5705 phase.
5706
5707 @note this is used by both the mysql_real_connect_nonblocking
5708
5709 @param mysql mysql
5710 @param data pointer to the plugin auth data (scramble) in the
5711 handshake packet
5712 @param data_len the length of the data
5713 @param data_plugin a plugin that data were prepared for
5714 or 0 if it's mysql_change_user()
5715 @param db initial db to use, can be 0
5716
5717 @retval NET_ASYNC_NOT_READY authentication not yet complete
5718 @retval NET_ASYNC_COMPLETE authentication done
5719 */
5720 25963 mysql_state_machine_status run_plugin_auth_nonblocking(MYSQL *mysql, char *data,
5721 uint data_len,
5722 const char *data_plugin,
5723 const char *db) {
5724
1/2
✓ Branch 0 taken 25963 times.
✗ Branch 1 not taken.
25963 DBUG_TRACE;
5725
2/6
✓ Branch 0 taken 25963 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25963 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
25963 mysql_async_auth *ctx = ASYNC_DATA(mysql)->connect_context->auth_context;
5726
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 25914 times.
25963 if (!ctx) {
5727 ctx = static_cast<mysql_async_auth *>(
5728
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 my_malloc(key_memory_MYSQL, sizeof(*ctx), MYF(MY_WME | MY_ZEROFILL)));
5729
5730 49 ctx->mysql = mysql;
5731 49 ctx->data = data;
5732 49 ctx->data_len = data_len;
5733 49 ctx->data_plugin = data_plugin;
5734 49 ctx->db = db;
5735 49 ctx->non_blocking = true;
5736 49 ctx->current_factor_index = 0;
5737 49 ctx->state_function = authsm_begin_plugin_auth;
5738
2/6
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
49 ASYNC_DATA(mysql)->connect_context->auth_context = ctx;
5739 }
5740
5741
1/2
✓ Branch 0 taken 25963 times.
✗ Branch 1 not taken.
25963 mysql_state_machine_status ret = ctx->state_function(ctx);
5742
4/4
✓ Branch 0 taken 25954 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 25914 times.
25963 if (ret == STATE_MACHINE_FAILED || ret == STATE_MACHINE_DONE) {
5743
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 my_free(ctx);
5744
2/6
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
49 ASYNC_DATA(mysql)->connect_context->auth_context = nullptr;
5745 }
5746
5747 25963 return ret;
5748 25963 }
5749
5750 /**
5751 Determine the default/initial plugin to use
5752 */
5753 168547 static mysql_state_machine_status authsm_begin_plugin_auth(
5754 mysql_async_auth *ctx) {
5755
1/2
✓ Branch 0 taken 168566 times.
✗ Branch 1 not taken.
168547 DBUG_TRACE;
5756 168566 MYSQL *mysql = ctx->mysql;
5757 168566 ctx->auth_plugin_name = nullptr;
5758
1/2
✓ Branch 0 taken 168567 times.
✗ Branch 1 not taken.
168566 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH &&
5759
2/2
✓ Branch 0 taken 168323 times.
✓ Branch 1 taken 244 times.
168567 ctx->data_plugin != nullptr) {
5760 /*
5761 LDAP SASL Kerberos and Native Karberos plug-in depends on client side set
5762 default plug-in to obtained user name from credential cache. If we don't
5763 use client side authentication plug-in, user and password less
5764 functionality will not work. And this is very important feature for
5765 Kerberos.
5766
5767 We are not overriding client side default authentication plug-in if
5768 it is configured in the client side. Once server supports configuration of
5769 all the authentication plug-ins as default, Below code shall be removed.
5770 Checks:
5771 1. Default authentication plug-in is configured
5772 2. Default authentication plug-in is valid.
5773 */
5774 168323 auth_plugin_t *client_plugin{nullptr};
5775
6/6
✓ Branch 0 taken 168322 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 174 times.
✓ Branch 3 taken 168148 times.
✓ Branch 4 taken 170 times.
✓ Branch 5 taken 168153 times.
168497 if (mysql->options.extension && mysql->options.extension->default_auth &&
5776
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 4 times.
174 (client_plugin = (auth_plugin_t *)mysql_client_find_plugin(
5777
1/2
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
174 mysql, mysql->options.extension->default_auth,
5778 MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) {
5779 170 ctx->auth_plugin_name = mysql->options.extension->default_auth;
5780 } else {
5781 168153 ctx->auth_plugin_name = ctx->data_plugin;
5782 }
5783
2/4
✓ Branch 0 taken 168321 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 168321 times.
168323 if (!(ctx->auth_plugin = (auth_plugin_t *)mysql_client_find_plugin(
5784 mysql, ctx->auth_plugin_name,
5785 MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) {
5786 /*
5787 Client didn't recognize the server default plugin.
5788 Fallback on any client plugin set as the default.
5789 */
5790 if (mysql->options.extension && mysql->options.extension->default_auth) {
5791 ctx->auth_plugin_name = mysql->options.extension->default_auth;
5792 if (!(ctx->auth_plugin = (auth_plugin_t *)mysql_client_find_plugin(
5793 mysql, ctx->auth_plugin_name,
5794 MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
5795 return STATE_MACHINE_FAILED; /* oops, not found */
5796 }
5797 }
5798 }
5799
5800
3/4
✓ Branch 0 taken 168313 times.
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 168321 times.
168564 if (ctx->auth_plugin_name == nullptr || ctx->auth_plugin == nullptr) {
5801 /*
5802 If everything else fail we use the built in plugin
5803 */
5804 243 ctx->auth_plugin = &caching_sha2_password_client_plugin;
5805 243 ctx->auth_plugin_name = ctx->auth_plugin->name;
5806 }
5807
5808
2/4
✓ Branch 0 taken 168547 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 168547 times.
168564 if (check_plugin_enabled(mysql, ctx)) return STATE_MACHINE_FAILED;
5809
5810
3/8
✓ Branch 0 taken 168560 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 168562 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 168562 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
168547 DBUG_PRINT("info", ("using plugin %s", ctx->auth_plugin_name));
5811
5812 168556 mysql->net.last_errno = 0; /* just in case */
5813
5814 /*
5815 data_plugin has the plugin the server wants us to use and
5816 auth_plugin_name has the plugin we think we will need.
5817 Server doesn't know what user the client will send yet.
5818 so client knows more than the server - hence we should use
5819 auth_plugin_name if it is different from ctx->data_plugin
5820 */
5821
4/4
✓ Branch 0 taken 168320 times.
✓ Branch 1 taken 236 times.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 168194 times.
168556 if (ctx->data_plugin && strcmp(ctx->data_plugin, ctx->auth_plugin_name)) {
5822 126 ctx->data = nullptr;
5823 126 ctx->data_len = 0;
5824 }
5825
5826 168556 ctx->mpvio.mysql_change_user = ctx->data_plugin == nullptr;
5827 168556 ctx->mpvio.cached_server_reply.pkt = (uchar *)ctx->data;
5828 168556 ctx->mpvio.cached_server_reply.pkt_len = ctx->data_len;
5829 /*
5830 Sometimes plugin provided data (like scramble) can be optional, in such a
5831 case we set pkt_received flag to false based on data length. This flag is
5832 later checked in client_mpvio_read_packet() to decide on to read from
5833 network or return the cached data.
5834 */
5835
2/2
✓ Branch 0 taken 369 times.
✓ Branch 1 taken 168187 times.
168556 if (ctx->data_len == 0)
5836 369 ctx->mpvio.cached_server_reply.pkt_received = false;
5837 else
5838 168187 ctx->mpvio.cached_server_reply.pkt_received = true;
5839 168556 ctx->mpvio.read_packet = client_mpvio_read_packet;
5840 168556 ctx->mpvio.write_packet = client_mpvio_write_packet;
5841 168556 ctx->mpvio.read_packet_nonblocking = client_mpvio_read_packet_nonblocking;
5842 168556 ctx->mpvio.write_packet_nonblocking = client_mpvio_write_packet_nonblocking;
5843 168556 ctx->mpvio.info = client_mpvio_info;
5844 168556 ctx->mpvio.mysql = mysql;
5845 168556 ctx->mpvio.packets_read = ctx->mpvio.packets_written = 0;
5846 168556 ctx->mpvio.db = ctx->db;
5847 168556 ctx->mpvio.plugin = ctx->auth_plugin;
5848 168556 ctx->client_auth_plugin_state =
5849 (int)(client_auth_caching_sha2_password_plugin_status::
5850 CACHING_SHA2_READING_PASSWORD);
5851
5852 168556 ctx->state_function = authsm_run_first_authenticate_user;
5853 168556 return STATE_MACHINE_CONTINUE;
5854 168556 }
5855
5856 /**
5857 Authentication can have two authenticate_user calls, depending on
5858 what the server responds with; this handles the first.
5859 */
5860 172141 static mysql_state_machine_status authsm_run_first_authenticate_user(
5861 mysql_async_auth *ctx) {
5862
1/2
✓ Branch 0 taken 172159 times.
✗ Branch 1 not taken.
172141 DBUG_TRACE;
5863 172159 MYSQL *mysql = ctx->mysql;
5864
2/8
✓ Branch 0 taken 161699 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 161699 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
161699 MYSQL_TRACE(AUTH_PLUGIN, mysql, (ctx->auth_plugin->name));
5865
5866
3/4
✓ Branch 0 taken 3642 times.
✓ Branch 1 taken 168517 times.
✓ Branch 2 taken 3642 times.
✗ Branch 3 not taken.
172159 if (ctx->non_blocking && ctx->auth_plugin->authenticate_user_nonblocking) {
5867 7284 net_async_status status = ctx->auth_plugin->authenticate_user_nonblocking(
5868
1/2
✓ Branch 0 taken 3642 times.
✗ Branch 1 not taken.
3642 (struct MYSQL_PLUGIN_VIO *)&ctx->mpvio, mysql, &ctx->res);
5869
2/2
✓ Branch 0 taken 3593 times.
✓ Branch 1 taken 49 times.
3642 if (status == NET_ASYNC_NOT_READY) {
5870 3593 return STATE_MACHINE_WOULD_BLOCK;
5871 }
5872 49 } else {
5873 168511 ctx->res = ctx->auth_plugin->authenticate_user(
5874
1/2
✓ Branch 0 taken 168511 times.
✗ Branch 1 not taken.
168517 (struct MYSQL_PLUGIN_VIO *)&ctx->mpvio, mysql);
5875 }
5876
5877 168560 ctx->state_function = authsm_handle_first_authenticate_user;
5878 168560 return STATE_MACHINE_CONTINUE;
5879 172153 }
5880
5881 /**
5882 Handle the result of the first authenticate_user.
5883 */
5884 168555 static mysql_state_machine_status authsm_handle_first_authenticate_user(
5885 mysql_async_auth *ctx) {
5886
1/2
✓ Branch 0 taken 168568 times.
✗ Branch 1 not taken.
168555 DBUG_TRACE;
5887 168568 MYSQL *mysql = ctx->mysql;
5888
3/14
✓ Branch 0 taken 168567 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 168567 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 168567 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
168568 DBUG_PRINT("info",
5889 ("authenticate_user returned %s",
5890 ctx->res == CR_OK
5891 ? "CR_OK"
5892 : ctx->res == CR_ERROR ? "CR_ERROR"
5893 : ctx->res == CR_OK_HANDSHAKE_COMPLETE
5894 ? "CR_OK_HANDSHAKE_COMPLETE"
5895 : "error"));
5896
5897 static_assert(CR_OK == -1, "");
5898 static_assert(CR_ERROR == 0, "");
5899
5900 /*
5901 The connection may be closed. If so: do not try to read from the buffer.
5902 If server sends OK packet without sending auth-switch first, client side
5903 auth plugin may not be able to process it correctly.
5904 However, if server sends OK, it means server side authentication plugin
5905 already performed required checks. Further, server side plugin did not
5906 really care about plugin used by client in this case.
5907 */
5908
4/4
✓ Branch 0 taken 1180 times.
✓ Branch 1 taken 167376 times.
✓ Branch 2 taken 217 times.
✓ Branch 3 taken 168339 times.
169736 if (ctx->res > CR_OK &&
5909
2/2
✓ Branch 0 taken 1178 times.
✓ Branch 1 taken 2 times.
1180 (!my_net_is_inited(&mysql->net) ||
5910
3/4
✓ Branch 0 taken 1178 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 215 times.
✓ Branch 3 taken 963 times.
1178 (mysql->net.read_pos[0] != 0 && mysql->net.read_pos[0] != 254))) {
5911 /*
5912 the plugin returned an error. write it down in mysql,
5913 unless the error code is CR_ERROR and mysql->net.last_errno
5914 is already set (the plugin has done it)
5915 */
5916
3/8
✓ Branch 0 taken 217 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 217 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 217 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
217 DBUG_PRINT("info", ("res=%d", ctx->res));
5917
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 217 times.
217 if (ctx->res > CR_ERROR)
5918 set_mysql_error(mysql, ctx->res, unknown_sqlstate);
5919
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 217 times.
217 else if (!mysql->net.last_errno)
5920 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
5921 217 return STATE_MACHINE_FAILED;
5922 }
5923 168339 ctx->state_function = authsm_read_change_user_result;
5924 168339 return STATE_MACHINE_CONTINUE;
5925 168556 }
5926
5927 /**
5928 After the first authenticate_user comes a call to read the result of the
5929 implied change_user.
5930 */
5931 190429 static mysql_state_machine_status authsm_read_change_user_result(
5932 mysql_async_auth *ctx) {
5933
1/2
✓ Branch 0 taken 190441 times.
✗ Branch 1 not taken.
190429 DBUG_TRACE;
5934 190441 MYSQL *mysql = ctx->mysql;
5935 /* read the OK packet (or use the cached value in mysql->net.read_pos */
5936
2/2
✓ Branch 0 taken 189478 times.
✓ Branch 1 taken 963 times.
190441 if (ctx->res == CR_OK) {
5937
2/2
✓ Branch 0 taken 22137 times.
✓ Branch 1 taken 167341 times.
189478 if (ctx->non_blocking) {
5938 net_async_status status =
5939
1/2
✓ Branch 0 taken 22137 times.
✗ Branch 1 not taken.
22137 (*mysql->methods->read_change_user_result_nonblocking)(
5940 mysql, &ctx->pkt_length);
5941
2/2
✓ Branch 0 taken 22091 times.
✓ Branch 1 taken 46 times.
22137 if (status == NET_ASYNC_NOT_READY) {
5942 22091 return STATE_MACHINE_WOULD_BLOCK;
5943 }
5944 } else {
5945
1/2
✓ Branch 0 taken 167340 times.
✗ Branch 1 not taken.
167341 ctx->pkt_length = (*mysql->methods->read_change_user_result)(mysql);
5946 }
5947 } else /* res == CR_OK_HANDSHAKE_COMPLETE */
5948 963 ctx->pkt_length = ctx->mpvio.last_read_packet_len;
5949
5950 168349 ctx->state_function = authsm_handle_change_user_result;
5951 168349 return STATE_MACHINE_CONTINUE;
5952 190440 }
5953
5954 /**
5955 Check if server asked to use a different authentication plugin
5956 */
5957 168348 static mysql_state_machine_status authsm_handle_change_user_result(
5958 mysql_async_auth *ctx) {
5959
1/2
✓ Branch 0 taken 168352 times.
✗ Branch 1 not taken.
168348 DBUG_TRACE;
5960 168352 MYSQL *mysql = ctx->mysql;
5961
3/8
✓ Branch 0 taken 168351 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 168351 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 168351 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
168352 DBUG_PRINT("info", ("OK packet length=%lu", ctx->pkt_length));
5962
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 167319 times.
168351 if (ctx->pkt_length == packet_error) {
5963
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1027 times.
1032 if (mysql->net.last_errno == CR_SERVER_LOST)
5964
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
5965 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
5966 5 "reading authorization packet", errno);
5967 1032 return STATE_MACHINE_FAILED;
5968 }
5969
5970
2/2
✓ Branch 0 taken 3034 times.
✓ Branch 1 taken 164285 times.
167319 if (mysql->net.read_pos[0] == 254) {
5971 3034 ctx->state_function = authsm_run_second_authenticate_user;
5972
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 164281 times.
164285 } else if (is_auth_next_factor_packet(mysql)) {
5973 ctx->state_function = authsm_init_multi_auth;
5974 } else {
5975
2/2
✓ Branch 0 taken 164280 times.
✓ Branch 1 taken 1 times.
164281 if (is_OK_packet(mysql, ctx->pkt_length)) {
5976
1/2
✓ Branch 0 taken 164284 times.
✗ Branch 1 not taken.
164280 read_ok_ex(mysql, ctx->pkt_length);
5977 164284 ctx->state_function = authsm_finish_auth;
5978 }
5979 }
5980
5981 167319 return STATE_MACHINE_CONTINUE;
5982 168351 }
5983
5984 /**
5985 Start the authentication process again with the plugin which
5986 server asked for.
5987 */
5988 3034 static mysql_state_machine_status authsm_run_second_authenticate_user(
5989 mysql_async_auth *ctx) {
5990
1/2
✓ Branch 0 taken 3034 times.
✗ Branch 1 not taken.
3034 DBUG_TRACE;
5991 3034 MYSQL *mysql = ctx->mysql;
5992 /* The server asked to use a different authentication plugin */
5993
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3034 times.
3034 if (ctx->pkt_length < 2) {
5994 set_mysql_error(mysql, CR_MALFORMED_PACKET,
5995 unknown_sqlstate); /* purecov: inspected */
5996 return STATE_MACHINE_FAILED;
5997 } else {
5998 /* "use different plugin" packet */
5999 uint len;
6000 3034 ctx->auth_plugin_name = (char *)mysql->net.read_pos + 1;
6001 3034 len = (uint)strlen(
6002 ctx->auth_plugin_name); /* safe as my_net_read always appends \0 */
6003 3034 ctx->mpvio.cached_server_reply.pkt_len = ctx->pkt_length - len - 2;
6004 3034 ctx->mpvio.cached_server_reply.pkt = mysql->net.read_pos + len + 2;
6005 3034 ctx->mpvio.cached_server_reply.pkt_received = true;
6006
3/8
✓ Branch 0 taken 3034 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3034 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3034 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3034 DBUG_PRINT("info", ("change plugin packet from server for plugin %s",
6007 ctx->auth_plugin_name));
6008 }
6009
2/4
✓ Branch 0 taken 3034 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3034 times.
3034 if (!(ctx->auth_plugin = (auth_plugin_t *)mysql_client_find_plugin(
6010 mysql, ctx->auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
6011 return STATE_MACHINE_FAILED;
6012
6013
3/4
✓ Branch 0 taken 3034 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3030 times.
3034 if (check_plugin_enabled(mysql, ctx)) return STATE_MACHINE_FAILED;
6014
6015
2/8
✓ Branch 0 taken 2800 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2800 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2800 MYSQL_TRACE(AUTH_PLUGIN, mysql, (ctx->auth_plugin->name));
6016
6017
2/6
✓ Branch 0 taken 3030 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3030 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3030 DBUG_EXECUTE_IF("simulate_fido_testing", {
6018 bool is_fido_testing = true;
6019 mysql_plugin_options((struct st_mysql_client_plugin *)ctx->auth_plugin,
6020 "is_fido_testing", &is_fido_testing);
6021 });
6022 3030 ctx->mpvio.plugin = ctx->auth_plugin;
6023 6060 ctx->res = ctx->auth_plugin->authenticate_user(
6024
1/2
✓ Branch 0 taken 3030 times.
✗ Branch 1 not taken.
3030 (struct MYSQL_PLUGIN_VIO *)&ctx->mpvio, mysql);
6025
6026 3030 ctx->state_function = authsm_handle_second_authenticate_user;
6027 3030 return STATE_MACHINE_CONTINUE;
6028 3034 }
6029
6030 /* Now read the results. */
6031 3030 static mysql_state_machine_status authsm_handle_second_authenticate_user(
6032 mysql_async_auth *ctx) {
6033
1/2
✓ Branch 0 taken 3030 times.
✗ Branch 1 not taken.
3030 DBUG_TRACE;
6034 3030 MYSQL *mysql = ctx->mysql;
6035
3/14
✓ Branch 0 taken 3030 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3030 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3030 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
3030 DBUG_PRINT("info",
6036 ("second authenticate_user returned %s",
6037 ctx->res == CR_OK
6038 ? "CR_OK"
6039 : ctx->res == CR_ERROR ? "CR_ERROR"
6040 : ctx->res == CR_OK_HANDSHAKE_COMPLETE
6041 ? "CR_OK_HANDSHAKE_COMPLETE"
6042 : "error"));
6043
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 2991 times.
3030 if (ctx->res > CR_OK) {
6044
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (ctx->res > CR_ERROR)
6045 set_mysql_error(mysql, ctx->res, unknown_sqlstate);
6046
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 else if (!mysql->net.last_errno)
6047 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
6048 39 return STATE_MACHINE_FAILED;
6049 }
6050
6051
1/2
✓ Branch 0 taken 2991 times.
✗ Branch 1 not taken.
2991 if (ctx->res != CR_OK_HANDSHAKE_COMPLETE) {
6052 /* Read what server thinks about out new auth message report */
6053
3/4
✓ Branch 0 taken 2991 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 469 times.
✓ Branch 3 taken 2522 times.
2991 if ((ctx->pkt_length = cli_safe_read(mysql, nullptr)) == packet_error) {
6054
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 469 times.
469 if (mysql->net.last_errno == CR_SERVER_LOST)
6055 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
6056 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
6057 "reading final connect information", errno);
6058 469 return STATE_MACHINE_FAILED;
6059 }
6060
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2522 times.
2522 if (is_auth_next_factor_packet(mysql)) {
6061 ctx->state_function = authsm_init_multi_auth;
6062 return STATE_MACHINE_CONTINUE;
6063
1/2
✓ Branch 0 taken 2522 times.
✗ Branch 1 not taken.
2522 } else if (is_OK_packet(mysql, ctx->pkt_length)) {
6064
1/2
✓ Branch 0 taken 2522 times.
✗ Branch 1 not taken.
2522 read_ok_ex(mysql, ctx->pkt_length);
6065 } else {
6066 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
6067 return STATE_MACHINE_FAILED;
6068 }
6069 }
6070 2522 ctx->state_function = authsm_finish_auth;
6071 2522 return STATE_MACHINE_CONTINUE;
6072 3030 }
6073
6074 /* Final cleanup */
6075 166803 static mysql_state_machine_status authsm_finish_auth(mysql_async_auth *ctx) {
6076
1/2
✓ Branch 0 taken 166807 times.
✗ Branch 1 not taken.
166803 DBUG_TRACE;
6077 166807 MYSQL *mysql = ctx->mysql;
6078 /*
6079 net->read_pos[0] should always be 0 here if the server implements
6080 the protocol correctly
6081 */
6082 166807 ctx->res = (mysql->net.read_pos[0] != 0);
6083
6084
2/8
✓ Branch 0 taken 156641 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 156641 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
156641 MYSQL_TRACE(AUTHENTICATED, mysql, ());
6085
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 166807 times.
333615 return ctx->res ? STATE_MACHINE_FAILED : STATE_MACHINE_DONE;
6086 166807 }
6087
6088 /** Start multi factor authentication */
6089 static mysql_state_machine_status authsm_init_multi_auth(
6090 mysql_async_auth *ctx) {
6091 DBUG_TRACE;
6092 MYSQL *mysql = ctx->mysql;
6093 /*
6094 If previous factor authentication is a success, read AuthNextFactor packet,
6095 extract client plugin name and plugin specific data and initiate next factor
6096 authentication.
6097 */
6098 size_t len;
6099 ctx->auth_plugin_name = (char *)mysql->net.read_pos + 1;
6100 len = strlen(ctx->auth_plugin_name);
6101 /* adjust cached plugin data packet */
6102 ctx->mpvio.cached_server_reply.pkt_len = ctx->pkt_length - len - 2;
6103 ctx->mpvio.cached_server_reply.pkt = mysql->net.read_pos + len + 2;
6104 ctx->mpvio.cached_server_reply.pkt_received = true;
6105 DBUG_PRINT("info", ("AuthNextFactor plugin packet from server %s",
6106 ctx->auth_plugin_name));
6107
6108 /* update current factor index to point to nth factor */
6109 ctx->current_factor_index++;
6110 if (!(ctx->auth_plugin = (auth_plugin_t *)mysql_client_find_plugin(
6111 mysql, ctx->auth_plugin_name,
6112 MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) {
6113 set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
6114 unknown_sqlstate,
6115 ER_CLIENT(CR_AUTH_PLUGIN_CANNOT_LOAD),
6116 ctx->auth_plugin_name, "plugin not available");
6117 return STATE_MACHINE_FAILED;
6118 }
6119 if (mysql->options.extension) {
6120 char **plugin_name =
6121 &mysql->options.extension->client_auth_info[ctx->current_factor_index]
6122 .plugin_name;
6123 *plugin_name = static_cast<char *>(
6124 my_malloc(PSI_NOT_INSTRUMENTED, len + 1, MYF(MY_WME | MY_ZEROFILL)));
6125 if (!*plugin_name) {
6126 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
6127 return STATE_MACHINE_FAILED;
6128 }
6129 memcpy(*plugin_name, ctx->auth_plugin_name, len);
6130 }
6131 DBUG_EXECUTE_IF("simulate_fido_testing", {
6132 bool is_fido_testing = true;
6133 mysql_plugin_options((struct st_mysql_client_plugin *)ctx->auth_plugin,
6134 "is_fido_testing", &is_fido_testing);
6135 });
6136 /* check if plugin is enabled */
6137 if (check_plugin_enabled(mysql, ctx)) return STATE_MACHINE_FAILED;
6138
6139 /* reset password for next client auth plugin */
6140 if (mysql->passwd) mysql->passwd[0] = 0;
6141 /* get password */
6142 if (mysql->options.extension &&
6143 mysql->options.extension->client_auth_info[ctx->current_factor_index]
6144 .password) {
6145 my_free(mysql->passwd);
6146 mysql->passwd = my_strdup(
6147 key_memory_MYSQL,
6148 mysql->options.extension->client_auth_info[ctx->current_factor_index]
6149 .password,
6150 MYF(0));
6151 }
6152 ctx->state_function = authsm_do_multi_plugin_auth;
6153 return STATE_MACHINE_CONTINUE;
6154 }
6155
6156 /** Invoke client plugins authentication method */
6157 static mysql_state_machine_status authsm_do_multi_plugin_auth(
6158 mysql_async_auth *ctx) {
6159 DBUG_TRACE;
6160 MYSQL *mysql = ctx->mysql;
6161 MYSQL_TRACE(AUTH_PLUGIN, mysql, (ctx->auth_plugin->name));
6162
6163 ctx->mpvio.plugin = ctx->auth_plugin;
6164 ctx->res = ctx->auth_plugin->authenticate_user(
6165 (struct MYSQL_PLUGIN_VIO *)&ctx->mpvio, mysql);
6166
6167 ctx->state_function = authsm_handle_multi_auth_response;
6168 return STATE_MACHINE_CONTINUE;
6169 }
6170
6171 /** Handle response from client plugins authentication method */
6172 static mysql_state_machine_status authsm_handle_multi_auth_response(
6173 mysql_async_auth *ctx) {
6174 DBUG_TRACE;
6175 MYSQL *mysql = ctx->mysql;
6176
6177 if (ctx->res > CR_OK) {
6178 if (ctx->res > CR_ERROR)
6179 set_mysql_error(mysql, ctx->res, unknown_sqlstate);
6180 else if (!mysql->net.last_errno)
6181 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
6182 return STATE_MACHINE_FAILED;
6183 }
6184
6185 if (ctx->res != CR_OK_HANDSHAKE_COMPLETE) {
6186 /* Read what server thinks about new auth message report */
6187 if ((ctx->pkt_length = cli_safe_read(mysql, nullptr)) == packet_error) {
6188 if (mysql->net.last_errno == CR_SERVER_LOST)
6189 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
6190 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
6191 "reading final connect information", errno);
6192 return STATE_MACHINE_FAILED;
6193 }
6194 if (is_auth_next_factor_packet(mysql)) {
6195 ctx->state_function = authsm_init_multi_auth;
6196 return STATE_MACHINE_CONTINUE;
6197 } else if (is_OK_packet(mysql, ctx->pkt_length)) {
6198 read_ok_ex(mysql, ctx->pkt_length);
6199 } else {
6200 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
6201 return STATE_MACHINE_FAILED;
6202 }
6203 }
6204 ctx->state_function = authsm_finish_auth;
6205 assert(ctx->current_factor_index < 3);
6206 return STATE_MACHINE_CONTINUE;
6207 }
6208
6209 /** set some default attributes */
6210 477687 static int set_connect_attributes(MYSQL *mysql, char *buff, size_t buf_len) {
6211
1/2
✓ Branch 0 taken 477744 times.
✗ Branch 1 not taken.
477687 DBUG_TRACE;
6212 477744 int rc = 0;
6213
6214 /*
6215 Clean up any values set by the client code. We want these options as
6216 consistent as possible
6217 */
6218
1/2
✓ Branch 0 taken 477719 times.
✗ Branch 1 not taken.
477744 rc += mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_name");
6219
1/2
✓ Branch 0 taken 477740 times.
✗ Branch 1 not taken.
477719 rc += mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_os");
6220
1/2
✓ Branch 0 taken 477746 times.
✗ Branch 1 not taken.
477740 rc += mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_platform");
6221
1/2
✓ Branch 0 taken 477748 times.
✗ Branch 1 not taken.
477746 rc += mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_pid");
6222
1/2
✓ Branch 0 taken 477742 times.
✗ Branch 1 not taken.
477748 rc += mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_thread");
6223
1/2
✓ Branch 0 taken 477741 times.
✗ Branch 1 not taken.
477742 rc += mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_version");
6224
6225 /*
6226 Now let's set up some values
6227 */
6228
1/2
✓ Branch 0 taken 477714 times.
✗ Branch 1 not taken.
477741 rc += mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_name",
6229 "libmysql");
6230
1/2
✓ Branch 0 taken 477731 times.
✗ Branch 1 not taken.
477714 rc += mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_version",
6231 PACKAGE_VERSION);
6232
1/2
✓ Branch 0 taken 477731 times.
✗ Branch 1 not taken.
477731 rc += mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_os", SYSTEM_TYPE);
6233
1/2
✓ Branch 0 taken 477732 times.
✗ Branch 1 not taken.
477731 rc += mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_platform",
6234 MACHINE_TYPE);
6235 #ifdef _WIN32
6236 snprintf(buff, buf_len, "%lu", (ulong)GetCurrentProcessId());
6237 #else
6238 477732 snprintf(buff, buf_len, "%lu", (ulong)getpid());
6239 #endif
6240
1/2
✓ Branch 0 taken 477736 times.
✗ Branch 1 not taken.
477723 rc += mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_pid", buff);
6241
6242 #ifdef _WIN32
6243 snprintf(buff, buf_len, "%lu", (ulong)GetCurrentThreadId());
6244 rc += mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_thread", buff);
6245 #endif
6246
6247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 477736 times.
955477 return rc > 0 ? 1 : 0;
6248 477736 }
6249
6250 477654 MYSQL *STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
6251 const char *user, const char *passwd,
6252 const char *db, uint port,
6253 const char *unix_socket, ulong client_flag) {
6254
1/2
✓ Branch 0 taken 477693 times.
✗ Branch 1 not taken.
477654 DBUG_TRACE;
6255 mysql_state_machine_status status;
6256 mysql_async_connect ctx;
6257 477693 memset(&ctx, 0, sizeof(ctx));
6258
6259 477693 ctx.mysql = mysql;
6260 477693 ctx.host = host;
6261 477693 ctx.port = port;
6262 477693 ctx.db = db;
6263 477693 ctx.user = user;
6264
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 477686 times.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
477693 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
6265 /* password will be extracted from mysql options */
6266
2/2
✓ Branch 0 taken 49723 times.
✓ Branch 1 taken 427970 times.
477693 if (mysql->options.extension->client_auth_info[0].password)
6267 49723 ctx.passwd = mysql->options.extension->client_auth_info[0].password;
6268 else
6269 427970 ctx.passwd = passwd;
6270 477693 ctx.unix_socket = unix_socket;
6271 477693 mysql->options.client_flag |= client_flag;
6272 477693 ctx.client_flag = mysql->options.client_flag;
6273 477693 ctx.state_function = csm_begin_connect;
6274 477693 ctx.ssl_state = SSL_NONE;
6275
6276 do {
6277
1/2
✓ Branch 0 taken 1642904 times.
✗ Branch 1 not taken.
1642897 status = ctx.state_function(&ctx);
6278
4/4
✓ Branch 0 taken 1331838 times.
✓ Branch 1 taken 311066 times.
✓ Branch 2 taken 1165204 times.
✓ Branch 3 taken 166634 times.
1642904 } while (status != STATE_MACHINE_FAILED && status != STATE_MACHINE_DONE);
6279
6280
2/2
✓ Branch 0 taken 166593 times.
✓ Branch 1 taken 311107 times.
477700 if (status == STATE_MACHINE_DONE) {
6281
3/8
✓ Branch 0 taken 166593 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 166593 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 166593 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
166593 DBUG_PRINT("exit", ("Mysql handler: %p", mysql));
6282 166593 return mysql;
6283 }
6284
6285
3/8
✓ Branch 0 taken 311107 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 311107 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 311107 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
311107 DBUG_PRINT("error", ("message: %u/%s (%s)", mysql->net.last_errno,
6286 mysql->net.sqlstate, mysql->net.last_error));
6287 {
6288 /* Free allocated memory */
6289
1/2
✓ Branch 0 taken 311107 times.
✗ Branch 1 not taken.
311107 end_server(mysql);
6290
1/2
✓ Branch 0 taken 311107 times.
✗ Branch 1 not taken.
311107 mysql_close_free(mysql);
6291
2/2
✓ Branch 0 taken 2046 times.
✓ Branch 1 taken 309061 times.
311107 if (!(ctx.client_flag & CLIENT_REMEMBER_OPTIONS))
6292
1/2
✓ Branch 0 taken 2046 times.
✗ Branch 1 not taken.
2046 mysql_close_free_options(mysql);
6293
3/4
✓ Branch 0 taken 723 times.
✓ Branch 1 taken 310384 times.
✓ Branch 2 taken 723 times.
✗ Branch 3 not taken.
311107 if (ctx.scramble_buffer_allocated) my_free(ctx.scramble_buffer);
6294 }
6295 311107 return nullptr;
6296 477700 }
6297
6298 /**
6299 This API attempts to initialize all the context needed to make an asynchronous
6300 connection followed by establishing a connection to MySQL database. If this
6301 API returns NET_ASYNC_COMPLETE then connection is established else call this
6302 API from the client application until the status returned is
6303 NET_ASYNC_COMPLETE.
6304
6305 @param[in] mysql connection handle
6306 @param[in] host host name or IP address
6307 @param[in] user login ID used to connect to host
6308 @param[in] passwd password for this login ID
6309 @param[in] db default database to be set after connection
6310 @param[in] port port number to use for connection
6311 @param[in] unix_socket socket file to use for connection
6312 @param[in] client_flag flag to indidcate what client can handle
6313
6314 @retval NET_ASYNC_COMPLETE Success.
6315 @retval NET_ASYNC_ERROR Error.
6316 */
6317 91352 net_async_status STDCALL mysql_real_connect_nonblocking(
6318 MYSQL *mysql, const char *host, const char *user, const char *passwd,
6319 const char *db, uint port, const char *unix_socket, ulong client_flag) {
6320
1/2
✓ Branch 0 taken 91352 times.
✗ Branch 1 not taken.
91352 DBUG_TRACE;
6321
6322 mysql_state_machine_status status;
6323
2/6
✓ Branch 0 taken 91352 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91352 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
91352 mysql_async_connect *ctx = ASYNC_DATA(mysql)->connect_context;
6324
6325
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 91301 times.
91352 if (!ctx) {
6326 ctx = static_cast<mysql_async_connect *>(
6327
1/2
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
51 my_malloc(key_memory_MYSQL, sizeof(*ctx), MYF(MY_WME | MY_ZEROFILL)));
6328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51 if (!ctx) return NET_ASYNC_ERROR;
6329
6330 51 ctx->mysql = mysql;
6331 51 ctx->host = host;
6332 51 ctx->port = port;
6333 51 ctx->db = db;
6334 51 ctx->user = user;
6335
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
51 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
6336 /* password will be extracted from mysql options */
6337
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 19 times.
51 if (mysql->options.extension->client_auth_info[0].password)
6338 32 ctx->passwd = mysql->options.extension->client_auth_info[0].password;
6339 else
6340 19 ctx->passwd = passwd;
6341 51 ctx->unix_socket = unix_socket;
6342 51 mysql->options.client_flag |= client_flag;
6343 51 ctx->client_flag = mysql->options.client_flag;
6344 51 ctx->non_blocking = true;
6345 51 ctx->state_function = csm_begin_connect;
6346 51 ctx->ssl_state = SSL_NONE;
6347
2/6
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
51 ASYNC_DATA(mysql)->connect_context = ctx;
6348
2/6
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
51 ASYNC_DATA(mysql)->async_op_status = ASYNC_OP_CONNECT;
6349 }
6350
6351 /*
6352 Continue to loop When different state returns STATE_MACHINE_CONTINUE, which
6353 means more work has to be done immediately and should not return to the
6354 caller.
6355 */
6356 do {
6357
1/2
✓ Branch 0 taken 91913 times.
✗ Branch 1 not taken.
91913 status = ctx->state_function(ctx);
6358
2/2
✓ Branch 0 taken 561 times.
✓ Branch 1 taken 91352 times.
91913 } while (status == STATE_MACHINE_CONTINUE);
6359
6360
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 91312 times.
91352 if (status == STATE_MACHINE_DONE) {
6361
3/8
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 40 times.
✗ Branch 7 not taken.
40 my_free(ASYNC_DATA(mysql)->connect_context);
6362
2/6
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
40 ASYNC_DATA(mysql)->connect_context = nullptr;
6363
2/6
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
40 ASYNC_DATA(mysql)->async_op_status = ASYNC_OP_UNSET;
6364 40 return NET_ASYNC_COMPLETE;
6365 }
6366
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 91302 times.
91312 if (status == STATE_MACHINE_FAILED) {
6367
3/8
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10 DBUG_PRINT("error", ("message: %u/%s (%s)", mysql->net.last_errno,
6368 mysql->net.sqlstate, mysql->net.last_error));
6369 /* Free allocated memory */
6370
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 end_server(mysql);
6371
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 mysql_close_free(mysql);
6372
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (!(mysql->options.client_flag & CLIENT_REMEMBER_OPTIONS))
6373
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 mysql_close_free_options(mysql);
6374 10 return NET_ASYNC_ERROR;
6375 }
6376 /*
6377 State machine returned STATE_MACHINE_WOULD_BLOCK, thus expecting caller to
6378 call this function again to continue with state machine once pending IO is
6379 completed.
6380 */
6381 91302 return NET_ASYNC_NOT_READY;
6382 91352 }
6383 /**
6384 Begin the connection to the server, including any DNS resolution
6385 necessary, socket configuration, etc.
6386 */
6387 477695 static mysql_state_machine_status csm_begin_connect(mysql_async_connect *ctx) {
6388 477695 MYSQL *mysql = ctx->mysql;
6389 477695 const char *host = ctx->host;
6390 477695 const char *user = ctx->user;
6391 477695 const char *passwd = ctx->passwd;
6392 477695 const char *db = ctx->db;
6393 477695 uint port = ctx->port;
6394 477695 const char *unix_socket = ctx->unix_socket;
6395 477695 ulong client_flag = ctx->client_flag;
6396 477695 bool connect_done =
6397 true; // this is true for most of the connect methods except sockets
6398
6399
1/2
✓ Branch 0 taken 477748 times.
✗ Branch 1 not taken.
477695 DBUG_TRACE;
6400
6401
3/14
✓ Branch 0 taken 477726 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 477723 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 477723 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
477748 DBUG_PRINT("enter",
6402 ("host: %s db: %s user: %s (client)", host ? host : "(Null)",
6403 db ? db : "(Null)", user ? user : "(Null)"));
6404
6405 477706 NET *net = &mysql->net;
6406 #ifdef _WIN32
6407 HANDLE hPipe = INVALID_HANDLE_VALUE;
6408 #endif
6409 #ifdef HAVE_SYS_UN_H
6410 struct sockaddr_un UNIXaddr;
6411 #endif
6412 /* Test whether we're already connected */
6413
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 477705 times.
477706 if (net->vio) {
6414
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 set_mysql_error(mysql, CR_ALREADY_CONNECTED, unknown_sqlstate);
6415 1 return STATE_MACHINE_FAILED;
6416 }
6417
6418
2/4
✓ Branch 0 taken 477732 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 477732 times.
477705 if (set_connect_attributes(mysql, ctx->buff, sizeof(ctx->buff)))
6419 return STATE_MACHINE_FAILED;
6420
6421 477732 mysql->methods = &client_methods;
6422 477732 net->vio = nullptr; /* If something goes wrong */
6423 477732 mysql->client_flag = 0; /* For handshake */
6424
6425 /* use default options */
6426
3/4
✓ Branch 0 taken 477728 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 477732 times.
477732 if (mysql->options.my_cnf_file || mysql->options.my_cnf_group) {
6427 mysql_read_default_options(
6428 &mysql->options,
6429 (mysql->options.my_cnf_file ? mysql->options.my_cnf_file : "my"),
6430 mysql->options.my_cnf_group);
6431 my_free(mysql->options.my_cnf_file);
6432 my_free(mysql->options.my_cnf_group);
6433 mysql->options.my_cnf_file = mysql->options.my_cnf_group = nullptr;
6434 }
6435
6436 /* Some empty-string-tests are done because of ODBC */
6437
3/4
✓ Branch 0 taken 475130 times.
✓ Branch 1 taken 2602 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 475141 times.
477732 if (!host || !host[0]) host = mysql->options.host;
6438
4/4
✓ Branch 0 taken 477693 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 477678 times.
477732 if (!user || !user[0]) {
6439 54 user = mysql->options.user;
6440
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 39 times.
54 if (!user) user = "";
6441 }
6442
2/2
✓ Branch 0 taken 181 times.
✓ Branch 1 taken 477551 times.
477732 if (!passwd) {
6443 181 passwd = mysql->options.password;
6444 #if !defined(MYSQL_SERVER)
6445
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 if (!passwd) passwd = getenv("MYSQL_PWD"); /* get it from environment */
6446 #endif
6447
1/2
✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
181 if (!passwd) passwd = "";
6448 }
6449
4/4
✓ Branch 0 taken 401470 times.
✓ Branch 1 taken 76262 times.
✓ Branch 2 taken 8154 times.
✓ Branch 3 taken 393316 times.
477732 if (!db || !db[0]) db = mysql->options.db;
6450
2/2
✓ Branch 0 taken 2544 times.
✓ Branch 1 taken 475188 times.
477732 if (!port) port = mysql->options.port;
6451
2/2
✓ Branch 0 taken 82718 times.
✓ Branch 1 taken 395014 times.
477732 if (!unix_socket) unix_socket = mysql->options.unix_socket;
6452
6453 477732 mysql->server_status = SERVER_STATUS_AUTOCOMMIT;
6454
3/8
✓ Branch 0 taken 477706 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 477699 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 477699 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
477732 DBUG_PRINT("info", ("Connecting"));
6455
6456
5/14
✓ Branch 0 taken 466640 times.
✓ Branch 1 taken 124 times.
✓ Branch 2 taken 124 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 466764 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 466764 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
466764 MYSQL_TRACE_STAGE(mysql, CONNECTING);
6457
2/8
✓ Branch 0 taken 466726 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 466731 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
466726 MYSQL_TRACE(CONNECTING, mysql, ());
6458
6459 #if defined(_WIN32)
6460 if ((!mysql->options.protocol ||
6461 mysql->options.protocol == MYSQL_PROTOCOL_MEMORY) &&
6462 (!host || !strcmp(host, LOCAL_HOST))) {
6463 HANDLE handle_map;
6464 DBUG_PRINT("info", ("Using shared memory"));
6465
6466 handle_map =
6467 create_shared_memory(mysql, net, get_win32_connect_timeout(mysql));
6468
6469 if (handle_map == INVALID_HANDLE_VALUE) {
6470 DBUG_PRINT("error",
6471 ("host: '%s' socket: '%s' shared memory: %s have_tcpip: %d",
6472 host ? host : "<null>", unix_socket ? unix_socket : "<null>",
6473 mysql->options.shared_memory_base_name, (int)have_tcpip));
6474 if (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY)
6475 return STATE_MACHINE_FAILED;
6476 /*
6477 Try also with PIPE or TCP/IP. Clear the error from
6478 create_shared_memory().
6479 */
6480
6481 net_clear_error(net);
6482 } else {
6483 mysql->options.protocol = MYSQL_PROTOCOL_MEMORY;
6484 unix_socket = 0;
6485 host = mysql->options.shared_memory_base_name;
6486 snprintf(ctx->host_info = ctx->buff, sizeof(ctx->buff) - 1,
6487 ER_CLIENT(CR_SHARED_MEMORY_CONNECTION), host);
6488 }
6489 }
6490 #endif /* _WIN32 */
6491 #if defined(HAVE_SYS_UN_H)
6492
1/2
✓ Branch 0 taken 477699 times.
✗ Branch 1 not taken.
477669 if (!net->vio &&
6493
2/2
✓ Branch 0 taken 251430 times.
✓ Branch 1 taken 226269 times.
477699 (!mysql->options.protocol ||
6494
4/4
✓ Branch 0 taken 245191 times.
✓ Branch 1 taken 6239 times.
✓ Branch 2 taken 82714 times.
✓ Branch 3 taken 388746 times.
477699 mysql->options.protocol == MYSQL_PROTOCOL_SOCKET) &&
6495
4/4
✓ Branch 0 taken 71793 times.
✓ Branch 1 taken 10921 times.
✓ Branch 2 taken 457963 times.
✓ Branch 3 taken 2576 times.
471460 (unix_socket || mysql_unix_port) &&
6496
2/2
✓ Branch 0 taken 342014 times.
✓ Branch 1 taken 115949 times.
457963 (!host || !strcmp(host, LOCAL_HOST))) {
6497 344590 my_socket sock = socket(AF_UNIX, SOCK_STREAM, 0);
6498
3/8
✓ Branch 0 taken 344595 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 344582 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 344582 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
344605 DBUG_PRINT("info", ("Using socket"));
6499
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 344569 times.
344569 if (sock == INVALID_SOCKET) {
6500 set_mysql_extended_error(mysql, CR_SOCKET_CREATE_ERROR, unknown_sqlstate,
6501 ER_CLIENT(CR_SOCKET_CREATE_ERROR), socket_errno);
6502 return STATE_MACHINE_FAILED;
6503 }
6504
6505 344635 net->vio =
6506
1/2
✓ Branch 0 taken 344635 times.
✗ Branch 1 not taken.
344569 vio_new(sock, VIO_TYPE_SOCKET, VIO_LOCALHOST | VIO_BUFFERED_READ);
6507
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 344635 times.
344635 if (!net->vio) {
6508 DBUG_PRINT("error", ("Unknow protocol %d ", mysql->options.protocol));
6509 set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
6510 closesocket(sock);
6511 return STATE_MACHINE_FAILED;
6512 }
6513
6514
3/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 344587 times.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
344635 if (ctx->non_blocking) vio_set_blocking_flag(net->vio, !ctx->non_blocking);
6515
6516 344635 host = LOCAL_HOST;
6517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 344635 times.
344635 if (!unix_socket) unix_socket = mysql_unix_port;
6518 344635 ctx->host_info = const_cast<char *>(ER_CLIENT(CR_LOCALHOST_CONNECTION));
6519
3/8
✓ Branch 0 taken 344604 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 344599 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 344599 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
344575 DBUG_PRINT("info", ("Using UNIX sock '%s'", unix_socket));
6520
6521 344599 memset(&UNIXaddr, 0, sizeof(UNIXaddr));
6522 344599 UNIXaddr.sun_family = AF_UNIX;
6523
1/2
✓ Branch 0 taken 344638 times.
✗ Branch 1 not taken.
344599 strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path) - 1);
6524
6525
3/4
✓ Branch 0 taken 344637 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 344637 times.
344638 if (mysql->options.extension && mysql->options.extension->retry_count)
6526 my_net_set_retry_count(net, mysql->options.extension->retry_count);
6527
6528
2/2
✓ Branch 0 taken 242529 times.
✓ Branch 1 taken 102101 times.
689268 if (vio_socket_connect(net->vio, (struct sockaddr *)&UNIXaddr,
6529
1/2
✓ Branch 0 taken 344630 times.
✗ Branch 1 not taken.
344570 sizeof(UNIXaddr), ctx->non_blocking,
6530 get_vio_connect_timeout(mysql), &connect_done)) {
6531
3/8
✓ Branch 0 taken 242529 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 242529 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 242529 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
242529 DBUG_PRINT("error",
6532 ("Got error %d on connect to local server", socket_errno));
6533
1/2
✓ Branch 0 taken 242529 times.
✗ Branch 1 not taken.
242529 set_mysql_extended_error(mysql, CR_CONNECTION_ERROR, unknown_sqlstate,
6534 ER_CLIENT(CR_CONNECTION_ERROR), unix_socket,
6535 242529 socket_errno);
6536
1/2
✓ Branch 0 taken 242529 times.
✗ Branch 1 not taken.
242529 vio_delete(net->vio);
6537 242529 net->vio = nullptr;
6538 242529 return STATE_MACHINE_FAILED;
6539 }
6540 102101 mysql->options.protocol = MYSQL_PROTOCOL_SOCKET;
6541 }
6542 #elif defined(_WIN32)
6543 if (!net->vio && (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
6544 (host && !strcmp(host, LOCAL_HOST_NAMEDPIPE)) ||
6545 (!have_tcpip && (unix_socket || (!host && is_NT()))))) {
6546 hPipe = create_named_pipe(mysql, get_win32_connect_timeout(mysql), &host,
6547 &unix_socket);
6548
6549 if (hPipe == INVALID_HANDLE_VALUE) {
6550 DBUG_PRINT(
6551 "error",
6552 ("host: '%s' socket: '%s' have_tcpip: %d", host ? host : "<null>",
6553 unix_socket ? unix_socket : "<null>", (int)have_tcpip));
6554 if (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
6555 (host && !strcmp(host, LOCAL_HOST_NAMEDPIPE)) ||
6556 (unix_socket && !strcmp(unix_socket, MYSQL_NAMEDPIPE)))
6557 return STATE_MACHINE_FAILED;
6558 /* Try also with TCP/IP */
6559 } else {
6560 net->vio = vio_new_win32pipe(hPipe);
6561 snprintf(ctx->host_info = ctx->buff, sizeof(ctx->buff) - 1,
6562 ER_CLIENT(CR_NAMEDPIPE_CONNECTION), unix_socket);
6563 }
6564 }
6565 #endif
6566
3/8
✓ Branch 0 taken 235189 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 235184 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 235184 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
235180 DBUG_PRINT("info",
6567 ("net->vio: %p protocol: %d", net->vio, mysql->options.protocol));
6568
4/4
✓ Branch 0 taken 133099 times.
✓ Branch 1 taken 102085 times.
✓ Branch 2 taken 6239 times.
✓ Branch 3 taken 126860 times.
235184 if (!net->vio && (!mysql->options.protocol ||
6569
1/2
✓ Branch 0 taken 6268 times.
✗ Branch 1 not taken.
6239 mysql->options.protocol == MYSQL_PROTOCOL_TCP)) {
6570 133133 struct addrinfo *res_lst, *client_bind_ai_lst = nullptr, hints, *t_res;
6571 char port_buf[NI_MAXSERV];
6572 133133 my_socket sock = INVALID_SOCKET;
6573 133133 int gai_errno, saved_error = 0, status = -1, bind_result = 0;
6574 133133 uint flags = VIO_BUFFERED_READ;
6575
6576 133133 unix_socket = nullptr; /* This is not used */
6577
6578
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 133103 times.
133133 if (!port) port = mysql_port;
6579
6580
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 133098 times.
133133 if (!host) host = LOCAL_HOST;
6581
6582 133133 snprintf(ctx->host_info = ctx->buff, sizeof(ctx->buff) - 1,
6583 ER_CLIENT(CR_TCP_CONNECTION), host);
6584
3/8
✓ Branch 0 taken 133088 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133087 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 133087 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
133085 DBUG_PRINT("info", ("Server name: '%s'. TCP sock: %d", host, port));
6585
6586 133087 memset(&hints, 0, sizeof(hints));
6587 133087 hints.ai_socktype = SOCK_STREAM;
6588 133087 hints.ai_protocol = IPPROTO_TCP;
6589 133087 hints.ai_family = AF_UNSPEC;
6590
6591
3/8
✓ Branch 0 taken 133090 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133092 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 133092 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
133087 DBUG_PRINT("info", ("IPV6 getaddrinfo %s", host));
6592 133092 snprintf(port_buf, NI_MAXSERV, "%d", port);
6593
1/2
✓ Branch 0 taken 133083 times.
✗ Branch 1 not taken.
133092 gai_errno = getaddrinfo(host, port_buf, &hints, &res_lst);
6594
6595
5/8
✓ Branch 0 taken 133087 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 133080 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
133083 DBUG_EXECUTE_IF("vio_client_use_localhost", {
6596 assert(strlen(host) == 255);
6597 gai_errno = getaddrinfo(LOCAL_HOST, port_buf, &hints, &res_lst);
6598 });
6599
6600
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 133066 times.
133087 if (gai_errno != 0) {
6601
3/8
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
21 DBUG_PRINT("info", ("IPV6 getaddrinfo error %d", gai_errno));
6602
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
6603 ER_CLIENT(CR_UNKNOWN_HOST), host, gai_errno);
6604 66534 return STATE_MACHINE_FAILED;
6605 }
6606
6607 /* Get address info for client bind name if it is provided */
6608
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 133047 times.
133066 if (mysql->options.bind_address) {
6609 19 int bind_gai_errno = 0;
6610
6611
3/8
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
19 DBUG_PRINT("info", ("Resolving addresses for client bind: '%s'",
6612 mysql->options.bind_address));
6613 /* Lookup address info for name */
6614
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 bind_gai_errno = getaddrinfo(mysql->options.bind_address, nullptr, &hints,
6615 &client_bind_ai_lst);
6616
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (bind_gai_errno) {
6617 DBUG_PRINT("info",
6618 ("client bind getaddrinfo error %d", bind_gai_errno));
6619 set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
6620 ER_CLIENT(CR_UNKNOWN_HOST),
6621 mysql->options.bind_address, bind_gai_errno);
6622
6623 freeaddrinfo(res_lst);
6624 return STATE_MACHINE_FAILED;
6625 }
6626
3/8
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
19 DBUG_PRINT("info", (" got address info for client bind name"));
6627 }
6628
6629 /*
6630 A hostname might map to multiple IP addresses (IPv4/IPv6). Go over the
6631 list of IP addresses until a successful connection can be established.
6632 For each IP address, attempt to bind the socket to each client address
6633 for the client-side bind hostname until the bind is successful.
6634 */
6635
3/8
✓ Branch 0 taken 133063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133065 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 133065 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
133066 DBUG_PRINT("info", ("Try connect on all addresses for host."));
6636
2/2
✓ Branch 0 taken 133061 times.
✓ Branch 1 taken 66516 times.
199577 for (t_res = res_lst; t_res; t_res = t_res->ai_next) {
6637
3/8
✓ Branch 0 taken 133062 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133065 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 133065 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
133061 DBUG_PRINT("info",
6638 ("Create socket, family: %d type: %d proto: %d",
6639 t_res->ai_family, t_res->ai_socktype, t_res->ai_protocol));
6640
6641 133065 sock = socket(t_res->ai_family, t_res->ai_socktype, t_res->ai_protocol);
6642
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 133057 times.
133057 if (sock == INVALID_SOCKET) {
6643 DBUG_PRINT("info", ("Socket created was invalid"));
6644 /* Try next address if there is one */
6645 saved_error = socket_errno;
6646 continue;
6647 }
6648
6649
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 133038 times.
133057 if (client_bind_ai_lst) {
6650 19 struct addrinfo *curr_bind_ai = nullptr;
6651
3/8
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
19 DBUG_PRINT("info", ("Attempting to bind socket to bind address(es)"));
6652
6653 /*
6654 We'll attempt to bind to each of the addresses returned, until
6655 we find one that works.
6656 If none works, we'll try the next destination host address
6657 (if any)
6658 */
6659 19 curr_bind_ai = client_bind_ai_lst;
6660
6661
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 4 times.
23 while (curr_bind_ai != nullptr) {
6662 /* Attempt to bind the socket to the given address */
6663 19 bind_result = bind(sock, curr_bind_ai->ai_addr,
6664 static_cast<int>(curr_bind_ai->ai_addrlen));
6665
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 4 times.
19 if (!bind_result) break; /* Success */
6666
6667
3/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4 DBUG_PRINT("info", ("bind failed, attempting another bind address"));
6668 /* Problem with the bind, move to next address if present */
6669 4 curr_bind_ai = curr_bind_ai->ai_next;
6670 }
6671
6672
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 15 times.
19 if (bind_result) {
6673 /*
6674 Could not bind to any client-side address with this destination
6675 Try the next destination address (if any)
6676 */
6677
3/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4 DBUG_PRINT("info", ("All bind attempts with this address failed"));
6678 4 saved_error = socket_errno;
6679
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 closesocket(sock);
6680 4 continue;
6681 }
6682
3/8
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
15 DBUG_PRINT("info", ("Successfully bound client side of socket"));
6683 }
6684
6685 /* Create a new Vio object to abstract the socket. */
6686
1/2
✓ Branch 0 taken 133051 times.
✗ Branch 1 not taken.
133051 if (!net->vio) {
6687
2/4
✓ Branch 0 taken 133065 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133065 times.
133051 if (!(net->vio = vio_new(sock, VIO_TYPE_TCPIP, flags))) {
6688 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
6689 closesocket(sock);
6690 freeaddrinfo(res_lst);
6691 if (client_bind_ai_lst) freeaddrinfo(client_bind_ai_lst);
6692 return STATE_MACHINE_FAILED;
6693 }
6694 }
6695 /* Just reinitialize if one is already allocated. */
6696 else if (vio_reset(net->vio, VIO_TYPE_TCPIP, sock, nullptr, flags)) {
6697 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
6698 closesocket(sock);
6699 freeaddrinfo(res_lst);
6700 if (client_bind_ai_lst) freeaddrinfo(client_bind_ai_lst);
6701 return STATE_MACHINE_FAILED;
6702 }
6703
6704
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 133062 times.
133065 if (ctx->non_blocking)
6705
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 vio_set_blocking_flag(net->vio, !ctx->non_blocking);
6706
6707
3/8
✓ Branch 0 taken 133057 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133060 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 133060 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
133065 DBUG_PRINT("info", ("Connect socket"));
6708
6709
2/4
✓ Branch 0 taken 133062 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133062 times.
133060 if (mysql->options.extension && mysql->options.extension->retry_count)
6710 my_net_set_retry_count(net, mysql->options.extension->retry_count);
6711
6712 133060 status = vio_socket_connect(
6713 133060 net->vio, t_res->ai_addr, (socklen_t)t_res->ai_addrlen,
6714
1/2
✓ Branch 0 taken 133066 times.
✗ Branch 1 not taken.
133060 ctx->non_blocking, get_vio_connect_timeout(mysql), &connect_done);
6715 /*
6716 Here we rely on vio_socket_connect() to return success only if
6717 the connect attempt was really successful. Otherwise we would
6718 stop trying another address, believing we were successful.
6719 */
6720
2/2
✓ Branch 0 taken 66557 times.
✓ Branch 1 taken 66509 times.
133066 if (!status) break;
6721
6722 /*
6723 Save either the socket error status or the error code of
6724 the failed vio_connection operation. It is necessary to
6725 avoid having it overwritten by later operations.
6726 */
6727 66509 saved_error = socket_errno;
6728
6729
3/8
✓ Branch 0 taken 66509 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66509 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 66509 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
66509 DBUG_PRINT("info", ("No success, try next address."));
6730 }
6731
3/8
✓ Branch 0 taken 133063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133066 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 133066 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
133073 DBUG_PRINT("info",
6732 ("End of connect attempts, sock: %d status: %d error: %d",
6733 sock, status, saved_error));
6734
6735 133066 freeaddrinfo(res_lst);
6736
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 133049 times.
133068 if (client_bind_ai_lst) freeaddrinfo(client_bind_ai_lst);
6737
6738
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 133067 times.
133067 if (sock == INVALID_SOCKET) {
6739 set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate,
6740 ER_CLIENT(CR_IPSOCK_ERROR), saved_error);
6741 return STATE_MACHINE_FAILED;
6742 }
6743
6744
2/2
✓ Branch 0 taken 66513 times.
✓ Branch 1 taken 66554 times.
133067 if (status) {
6745
3/8
✓ Branch 0 taken 66513 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66513 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 66513 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
66513 DBUG_PRINT("error",
6746 ("Got error %d on connect to '%s'", saved_error, host));
6747
1/2
✓ Branch 0 taken 66513 times.
✗ Branch 1 not taken.
66513 set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
6748 ER_CLIENT(CR_CONN_HOST_ERROR), host, port,
6749 saved_error);
6750 66513 return STATE_MACHINE_FAILED;
6751 }
6752 }
6753
6754
2/2
✓ Branch 0 taken 168603 times.
✓ Branch 1 taken 2 times.
168605 ctx->state_function = connect_done ? csm_complete_connect : csm_wait_connect;
6755 168605 ctx->host = host;
6756 168605 ctx->user = user;
6757 168605 ctx->passwd = passwd;
6758 168605 ctx->db = db;
6759 168605 ctx->port = port;
6760 168605 ctx->unix_socket = unix_socket;
6761 168605 ctx->client_flag = client_flag;
6762 168605 return STATE_MACHINE_CONTINUE;
6763 477669 }
6764
6765 /**
6766 Wait for async connect attempt to complete.
6767 */
6768 2 static mysql_state_machine_status csm_wait_connect(mysql_async_connect *ctx) {
6769 2 NET *net = &(ctx->mysql->net);
6770 2 MYSQL_VIO vio = net->vio;
6771 2 int timeout_ms = 1; // this is 1ms: the smallest non-zero timeout we can use
6772 int ret;
6773
6774
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 DBUG_TRACE;
6775
6776
3/14
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
2 DBUG_PRINT(
6777 "enter",
6778 ("host: %s db: %s user: %s (client)", ctx->host ? ctx->host : "(Null)",
6779 ctx->db ? ctx->db : "(Null)", ctx->user ? ctx->user : "(Null)"));
6780
6781
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!net->vio) {
6782 DBUG_PRINT("error", ("Unknown protocol %d", ctx->mysql->options.protocol));
6783 set_mysql_error(ctx->mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
6784 return STATE_MACHINE_FAILED;
6785 }
6786
6787 /*
6788 The connect() is in progress. The vio_io_wait() with the smallest non-zero
6789 timeout possible can be used to peek if connect() completed.
6790
6791 If vio_io_wait() returns 0,
6792 the socket never became writable or there is timeout and we'll return
6793 to caller.
6794 Otherwise, if vio_io_wait() returns 1, then one of two conditions
6795 exist:
6796
6797 1. An error occurred. Use getsockopt() to check for this.
6798 2. The connection was set up successfully: getsockopt() will
6799 return 0 as an error.
6800 */
6801
6802
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 int io_wait_ret = vio_io_wait(vio, VIO_IO_EVENT_CONNECT, timeout_ms);
6803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (io_wait_ret == 0) return STATE_MACHINE_WOULD_BLOCK;
6804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (io_wait_ret == -1) return STATE_MACHINE_FAILED;
6805
6806 int error;
6807 2 IF_WIN(int, socklen_t) optlen = sizeof(error);
6808 2 IF_WIN(char, void) *optval = (IF_WIN(char, void) *)&error;
6809
6810 /*
6811 At this point, we know that something happened on the socket.
6812 But this does not means that everything is alright. The connect
6813 might have failed. We need to retrieve the error code from the
6814 socket layer. We must return success only if we are sure that
6815 it was really a success. Otherwise we might prevent the caller
6816 from trying another address to connect to.
6817 */
6818
3/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2 DBUG_PRINT("info", ("Connect to '%s' completed", ctx->host));
6819 2 ctx->state_function = csm_complete_connect;
6820
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (!(ret = mysql_socket_getsockopt(vio->mysql_socket, SOL_SOCKET, SO_ERROR,
6821 optval, &optlen))) {
6822 #ifdef _WIN32
6823 WSASetLastError(error);
6824 #else
6825 2 errno = error;
6826 #endif
6827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (error != 0) {
6828 DBUG_PRINT("error",
6829 ("Got error %d on connect to '%s'", error, ctx->host));
6830 set_mysql_extended_error(ctx->mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
6831 ER_CLIENT(CR_CONN_HOST_ERROR), ctx->host,
6832 ctx->port, error);
6833 return STATE_MACHINE_FAILED;
6834 }
6835 }
6836 2 return STATE_MACHINE_CONTINUE;
6837 2 }
6838
6839 /**
6840 Complete the connection itself, setting options on the now-connected socket.
6841 */
6842 168610 static mysql_state_machine_status csm_complete_connect(
6843 mysql_async_connect *ctx) {
6844
1/2
✓ Branch 0 taken 168670 times.
✗ Branch 1 not taken.
168610 DBUG_TRACE;
6845 168670 MYSQL *mysql = ctx->mysql;
6846 168670 NET *net = &mysql->net;
6847
3/8
✓ Branch 0 taken 168659 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 168643 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 168643 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
168670 DBUG_PRINT("info", ("net->vio: %p", net->vio));
6848
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 168613 times.
168621 if (!net->vio) {
6849
3/8
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
8 DBUG_PRINT("error", ("Unknow protocol %d ", mysql->options.protocol));
6850
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
6851 8 return STATE_MACHINE_FAILED;
6852 }
6853
6854
2/4
✓ Branch 0 taken 168647 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 168647 times.
168613 if (my_net_init(net, net->vio)) {
6855 vio_delete(net->vio);
6856 net->vio = nullptr;
6857 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
6858 return STATE_MACHINE_FAILED;
6859 }
6860
1/2
✓ Branch 0 taken 168663 times.
✗ Branch 1 not taken.
168647 vio_keepalive(net->vio, true);
6861
6862 /* If user set read_timeout, let it override the default */
6863
2/2
✓ Branch 0 taken 13672 times.
✓ Branch 1 taken 154991 times.
168663 if (mysql->options.read_timeout)
6864
1/2
✓ Branch 0 taken 13672 times.
✗ Branch 1 not taken.
13672 my_net_set_read_timeout(net, mysql->options.read_timeout);
6865
6866 /* If user set write_timeout, let it override the default */
6867
2/2
✓ Branch 0 taken 432 times.
✓ Branch 1 taken 168231 times.
168663 if (mysql->options.write_timeout)
6868
1/2
✓ Branch 0 taken 432 times.
✗ Branch 1 not taken.
432 my_net_set_write_timeout(net, mysql->options.write_timeout);
6869
6870 /* If user set retry_count, let it override the default */
6871
3/4
✓ Branch 0 taken 168662 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 168662 times.
168663 if (mysql->options.extension && mysql->options.extension->retry_count)
6872 my_net_set_retry_count(net, mysql->options.extension->retry_count);
6873
6874
2/2
✓ Branch 0 taken 8163 times.
✓ Branch 1 taken 160479 times.
168642 if (mysql->options.max_allowed_packet)
6875 8163 net->max_packet_size = mysql->options.max_allowed_packet;
6876
6877
2/8
✓ Branch 0 taken 158136 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 158140 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
158136 MYSQL_TRACE(CONNECTED, mysql, ());
6878
3/10
✓ Branch 0 taken 158139 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 158139 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
158140 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_INIT_PACKET);
6879
6880 /* Get version info */
6881 168645 mysql->protocol_version = PROTOCOL_VERSION; /* Assume this */
6882
6/6
✓ Branch 0 taken 126562 times.
✓ Branch 1 taken 42083 times.
✓ Branch 2 taken 126521 times.
✓ Branch 3 taken 41 times.
✓ Branch 4 taken 26 times.
✓ Branch 5 taken 168602 times.
295149 if (mysql->options.connect_timeout && !ctx->non_blocking &&
6883
3/4
✓ Branch 0 taken 126504 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 126478 times.
126521 (vio_io_wait(net->vio, VIO_IO_EVENT_READ,
6884 get_vio_connect_timeout(mysql)) < 1)) {
6885
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
6886 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
6887 "waiting for initial communication packet",
6888 26 socket_errno);
6889 26 return STATE_MACHINE_FAILED;
6890 }
6891 168602 ctx->state_function = csm_read_greeting;
6892 168602 return STATE_MACHINE_CONTINUE;
6893 168636 }
6894
6895 /**
6896 Read the greeting from the server that is read the first packet
6897 */
6898 220500 static mysql_state_machine_status csm_read_greeting(mysql_async_connect *ctx) {
6899
1/2
✓ Branch 0 taken 220532 times.
✗ Branch 1 not taken.
220500 DBUG_TRACE;
6900 220532 MYSQL *mysql = ctx->mysql;
6901
3/8
✓ Branch 0 taken 220523 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 220512 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 220512 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
220532 DBUG_PRINT("info", ("Read first packet."));
6902
6903
2/2
✓ Branch 0 taken 168575 times.
✓ Branch 1 taken 51937 times.
220512 if (!ctx->non_blocking)
6904
1/2
✓ Branch 0 taken 168594 times.
✗ Branch 1 not taken.
168575 ctx->pkt_length = cli_safe_read(mysql, nullptr);
6905 else {
6906
3/4
✓ Branch 0 taken 51937 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51887 times.
✓ Branch 3 taken 50 times.
51937 if (cli_safe_read_nonblocking(mysql, nullptr, &ctx->pkt_length) ==
6907 NET_ASYNC_NOT_READY) {
6908 51887 return STATE_MACHINE_WOULD_BLOCK;
6909 }
6910 }
6911
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 168424 times.
168644 if (ctx->pkt_length == packet_error) {
6912
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 177 times.
220 if (mysql->net.last_errno == CR_SERVER_LOST)
6913
1/2
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
43 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
6914 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
6915 "reading initial communication packet",
6916 43 socket_errno);
6917 220 return STATE_MACHINE_FAILED;
6918 }
6919 168424 ctx->state_function = csm_parse_handshake;
6920 168424 return STATE_MACHINE_CONTINUE;
6921 220531 }
6922
6923 /**
6924 Parse the handshake from the server.
6925 */
6926 168422 static mysql_state_machine_status csm_parse_handshake(
6927 mysql_async_connect *ctx) {
6928
1/2
✓ Branch 0 taken 168432 times.
✗ Branch 1 not taken.
168422 DBUG_TRACE;
6929 168432 MYSQL *mysql = ctx->mysql;
6930 168432 NET *net = &mysql->net;
6931 168432 int pkt_length = ctx->pkt_length;
6932 168432 int pkt_scramble_len = 0;
6933 char *end, *server_version_end, *pkt_end;
6934 168432 pkt_end = (char *)net->read_pos + pkt_length;
6935 /* Check if version of protocol matches current one */
6936 168432 mysql->protocol_version = net->read_pos[0];
6937
1/2
✓ Branch 0 taken 168427 times.
✗ Branch 1 not taken.
168432 DBUG_DUMP("packet", (uchar *)net->read_pos, 10);
6938
3/8
✓ Branch 0 taken 168431 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 168428 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 168428 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
168427 DBUG_PRINT("info", ("mysql protocol version %d, server=%d", PROTOCOL_VERSION,
6939 mysql->protocol_version));
6940
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 168427 times.
168428 if (mysql->protocol_version != PROTOCOL_VERSION) {
6941
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 set_mysql_extended_error(mysql, CR_VERSION_ERROR, unknown_sqlstate,
6942 ER_CLIENT(CR_VERSION_ERROR),
6943 mysql->protocol_version, PROTOCOL_VERSION);
6944 1 return STATE_MACHINE_FAILED;
6945 }
6946 168427 server_version_end = end = strend((char *)net->read_pos + 1);
6947 168429 mysql->thread_id = uint4korr((uchar *)end + 1);
6948 168429 end += 5;
6949 /*
6950 Scramble is split into two parts because old clients do not understand
6951 long scrambles; here goes the first part.
6952 */
6953 168429 ctx->scramble_data = end;
6954 168429 ctx->scramble_data_len = AUTH_PLUGIN_DATA_PART_1_LENGTH + 1;
6955 168429 ctx->scramble_plugin = nullptr;
6956 168429 end += ctx->scramble_data_len;
6957
6958
2/2
✓ Branch 0 taken 168426 times.
✓ Branch 1 taken 3 times.
168429 if (pkt_end >= end + 1) mysql->server_capabilities = uint2korr((uchar *)end);
6959
2/2
✓ Branch 0 taken 168423 times.
✓ Branch 1 taken 6 times.
168429 if (pkt_end >= end + 18) {
6960 /* New protocol with 16 bytes to describe server characteristics */
6961 168423 mysql->server_language = end[2];
6962 168423 mysql->server_status = uint2korr((uchar *)end + 3);
6963 168425 mysql->server_capabilities |= uint2korr((uchar *)end + 5) << 16;
6964 168427 pkt_scramble_len = end[7];
6965
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 168427 times.
168427 if (pkt_scramble_len < 0) {
6966 set_mysql_error(mysql, CR_MALFORMED_PACKET,
6967 unknown_sqlstate); /* purecov: inspected */
6968 return STATE_MACHINE_FAILED;
6969 }
6970 }
6971 168433 end += 18;
6972
6973
2/4
✓ Branch 0 taken 168420 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 168420 times.
168433 if (mysql_init_character_set(mysql)) return STATE_MACHINE_FAILED;
6974
6975 /* Save connection information */
6976 66339 if (!my_multi_malloc(
6977 key_memory_MYSQL, MYF(0), &mysql->host_info,
6978 168420 (uint)strlen(ctx->host_info) + 1, &mysql->host,
6979
1/2
✓ Branch 0 taken 168432 times.
✗ Branch 1 not taken.
168420 (uint)strlen(ctx->host) + 1, &mysql->unix_socket,
6980 102081 ctx->unix_socket ? (uint)strlen(ctx->unix_socket) + 1 : (uint)1,
6981 &mysql->server_version,
6982
2/2
✓ Branch 0 taken 102081 times.
✓ Branch 1 taken 66339 times.
168420 (uint)(server_version_end - (char *)net->read_pos + 1), NullS) ||
6983
5/8
✓ Branch 0 taken 168431 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 168429 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 168431 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 168415 times.
336848 !(mysql->user = my_strdup(key_memory_MYSQL, ctx->user, MYF(0))) ||
6984
2/4
✓ Branch 0 taken 168416 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 168420 times.
168431 !(mysql->passwd = my_strdup(key_memory_MYSQL, ctx->passwd, MYF(0)))) {
6985 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
6986 return STATE_MACHINE_FAILED;
6987 }
6988 168415 my_stpcpy(mysql->host_info, ctx->host_info);
6989 168419 my_stpcpy(mysql->host, ctx->host);
6990
2/2
✓ Branch 0 taken 102082 times.
✓ Branch 1 taken 66340 times.
168422 if (ctx->unix_socket)
6991 102082 my_stpcpy(mysql->unix_socket, ctx->unix_socket);
6992 else
6993 66340 mysql->unix_socket = nullptr;
6994 168421 my_stpcpy(mysql->server_version, (char *)net->read_pos + 1);
6995 168420 mysql->port = ctx->port;
6996
6997
2/2
✓ Branch 0 taken 168419 times.
✓ Branch 1 taken 1 times.
168420 if (pkt_end >= end + SCRAMBLE_LENGTH - AUTH_PLUGIN_DATA_PART_1_LENGTH + 1)
6998
6999 {
7000 /*
7001 move the first scramble part - directly in the NET buffer -
7002 to get a full continuous scramble. We've read all the header,
7003 and can overwrite it now.
7004 */
7005 168419 memmove(end - AUTH_PLUGIN_DATA_PART_1_LENGTH, ctx->scramble_data,
7006 AUTH_PLUGIN_DATA_PART_1_LENGTH);
7007 168419 ctx->scramble_data = end - AUTH_PLUGIN_DATA_PART_1_LENGTH;
7008
1/2
✓ Branch 0 taken 168419 times.
✗ Branch 1 not taken.
168419 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH) {
7009 168419 ctx->scramble_data_len = pkt_scramble_len;
7010 168419 ctx->scramble_plugin = ctx->scramble_data + ctx->scramble_data_len;
7011 /*
7012 There is a possibility that we did not get a correct plugin name
7013 for some reason. For example, the packet was malformed and some
7014 of the fields had incorrect values. In such cases, we keep the
7015 plugin name empty so that the default authentication plugin
7016 gets used later on. Since we don't really know the plugin for which
7017 the scramble_data was prepared, we can discard it and set it's length
7018 to 0.
7019 */
7020
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 168419 times.
168419 if (ctx->scramble_data + ctx->scramble_data_len > pkt_end) {
7021 ctx->scramble_data = nullptr;
7022 ctx->scramble_data_len = 0;
7023 ctx->scramble_plugin = const_cast<char *>("");
7024 }
7025 } else {
7026 ctx->scramble_data_len = (int)(pkt_end - ctx->scramble_data);
7027 ctx->scramble_plugin = caching_sha2_password_plugin_name;
7028 }
7029 } else {
7030
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
1 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
7031 return STATE_MACHINE_FAILED;
7032 }
7033 168419 ctx->state_function = csm_establish_ssl;
7034 168419 return STATE_MACHINE_CONTINUE;
7035 168420 }
7036
7037 /**
7038 Establish SSL if needed.
7039 */
7040 182148 static mysql_state_machine_status csm_establish_ssl(mysql_async_connect *ctx) {
7041
1/2
✓ Branch 0 taken 182160 times.
✗ Branch 1 not taken.
182148 DBUG_TRACE;
7042 182160 MYSQL *mysql = ctx->mysql;
7043 /* This check happens to work for both sync and async. */
7044
2/2
✓ Branch 0 taken 168430 times.
✓ Branch 1 taken 13730 times.
182160 if (ctx->ssl_state == SSL_NONE) {
7045
2/8
✓ Branch 0 taken 157948 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 157948 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
157948 MYSQL_TRACE(INIT_PACKET_RECEIVED, mysql,
7046 (ctx->pkt_length, mysql->net.read_pos));
7047
3/10
✓ Branch 0 taken 157947 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 157947 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
157948 MYSQL_TRACE_STAGE(mysql, AUTHENTICATE);
7048
7049 #if defined(_WIN32)
7050 if ((mysql->options.extension &&
7051 mysql->options.extension->ssl_mode <= SSL_MODE_PREFERRED) &&
7052 (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY ||
7053 mysql->options.protocol == MYSQL_PROTOCOL_PIPE)) {
7054 mysql->options.extension->ssl_mode = SSL_MODE_DISABLED;
7055 }
7056 #endif
7057 /* try and bring up SSL if possible */
7058 168429 cli_calculate_client_flag(mysql, ctx->db, ctx->client_flag);
7059
7060 /*
7061 Allocate separate buffer for scramble data if we are going
7062 to attempt TLS connection. This would prevent a possible
7063 overwrite through my_net_write.
7064 */
7065
3/4
✓ Branch 0 taken 168426 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 168429 times.
✗ Branch 3 not taken.
168427 if (ctx->scramble_data_len && mysql->options.extension &&
7066
2/2
✓ Branch 0 taken 24182 times.
✓ Branch 1 taken 144247 times.
168429 mysql->options.extension->ssl_mode != SSL_MODE_DISABLED) {
7067 24180 if (!(ctx->scramble_buffer =
7068
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24180 times.
24180 (char *)my_malloc(key_memory_MYSQL_HANDSHAKE,
7069
1/2
✓ Branch 0 taken 24180 times.
✗ Branch 1 not taken.
24182 ctx->scramble_data_len, MYF(MY_WME)))) {
7070 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
7071 return STATE_MACHINE_FAILED;
7072 }
7073 24180 ctx->scramble_buffer_allocated = true;
7074 24180 memcpy(ctx->scramble_buffer, ctx->scramble_data, ctx->scramble_data_len);
7075 } else {
7076 144245 ctx->scramble_buffer = ctx->scramble_data;
7077 }
7078 }
7079
2/2
✓ Branch 0 taken 13780 times.
✓ Branch 1 taken 168375 times.
182155 if (ctx->non_blocking) {
7080 int ret;
7081
3/4
✓ Branch 0 taken 13780 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13731 times.
✓ Branch 3 taken 49 times.
13780 if (cli_establish_ssl_nonblocking(mysql, &ret) == NET_ASYNC_NOT_READY) {
7082 13731 return STATE_MACHINE_WOULD_BLOCK;
7083 }
7084
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
49 if (ret) {
7085 return STATE_MACHINE_FAILED;
7086 }
7087 } else {
7088
3/4
✓ Branch 0 taken 168360 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 106 times.
✓ Branch 3 taken 168254 times.
168375 if (cli_establish_ssl(mysql)) {
7089 106 return STATE_MACHINE_FAILED;
7090 }
7091 }
7092
7093 168303 ctx->state_function = csm_authenticate;
7094 168303 return STATE_MACHINE_CONTINUE;
7095 182140 }
7096
7097 /**
7098 Invoke the authentication client plugin API to send the authentication
7099 data to the server
7100 */
7101 194222 static mysql_state_machine_status csm_authenticate(mysql_async_connect *ctx) {
7102
1/2
✓ Branch 0 taken 194237 times.
✗ Branch 1 not taken.
194222 DBUG_TRACE;
7103 194237 MYSQL *mysql = ctx->mysql;
7104
2/2
✓ Branch 0 taken 25963 times.
✓ Branch 1 taken 168274 times.
194237 if (ctx->non_blocking) {
7105 51926 mysql_state_machine_status status = run_plugin_auth_nonblocking(
7106
1/2
✓ Branch 0 taken 25963 times.
✗ Branch 1 not taken.
25963 ctx->mysql, ctx->scramble_data, ctx->scramble_data_len,
7107 ctx->scramble_plugin, ctx->db);
7108
2/2
✓ Branch 0 taken 25923 times.
✓ Branch 1 taken 40 times.
25963 if (status != STATE_MACHINE_DONE) {
7109 25923 return status;
7110 }
7111 } else {
7112
3/4
✓ Branch 0 taken 168272 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1683 times.
✓ Branch 3 taken 166589 times.
168274 if (run_plugin_auth(mysql, ctx->scramble_buffer, ctx->scramble_data_len,
7113 ctx->scramble_plugin, ctx->db)) {
7114 1683 return STATE_MACHINE_FAILED;
7115 }
7116 }
7117
7118
2/2
✓ Branch 0 taken 23451 times.
✓ Branch 1 taken 143178 times.
166629 if (ctx->scramble_buffer_allocated) {
7119 23451 ctx->scramble_buffer_allocated = false;
7120
1/2
✓ Branch 0 taken 23452 times.
✗ Branch 1 not taken.
23451 my_free(ctx->scramble_buffer);
7121 23452 ctx->scramble_buffer = nullptr;
7122 }
7123
7124 166630 ctx->state_function = csm_prep_select_database;
7125 166630 return STATE_MACHINE_CONTINUE;
7126 194236 }
7127
7128 /**
7129 Authenticated, set initial database if specified
7130 */
7131 166630 static mysql_state_machine_status csm_prep_select_database(
7132 mysql_async_connect *ctx) {
7133
1/2
✓ Branch 0 taken 166634 times.
✗ Branch 1 not taken.
166630 DBUG_TRACE;
7134 166634 MYSQL *mysql = ctx->mysql;
7135 166634 NET *net = &mysql->net;
7136
7137
2/10
✓ Branch 0 taken 156467 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 156467 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
156467 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
7138
7139 /* We will use compression */
7140
2/2
✓ Branch 0 taken 166516 times.
✓ Branch 1 taken 118 times.
166634 if ((mysql->client_flag & CLIENT_COMPRESS) ||
7141
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 166430 times.
166516 (mysql->client_flag & CLIENT_ZSTD_COMPRESSION_ALGORITHM)) {
7142 204 net->compress = true;
7143 uint compress_level;
7144 204 enum enum_compression_algorithm algorithm =
7145
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 86 times.
204 mysql->client_flag & CLIENT_COMPRESS ? MYSQL_ZLIB : MYSQL_ZSTD;
7146
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 if (mysql->options.extension &&
7147
2/2
✓ Branch 0 taken 197 times.
✓ Branch 1 taken 7 times.
204 mysql->options.extension->zstd_compression_level)
7148 197 compress_level = mysql->options.extension->zstd_compression_level;
7149 else
7150
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 compress_level = mysql_default_compression_level(algorithm);
7151 #ifndef MYSQL_SERVER
7152 135 NET_EXTENSION *ext = NET_EXTENSION_PTR(net);
7153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 assert(ext != nullptr);
7154
1/2
✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
135 mysql_compress_context_init(&ext->compress_ctx, algorithm, compress_level);
7155 #else
7156 69 NET_SERVER *server_ext = static_cast<NET_SERVER *>(net->extension);
7157
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 if (server_ext == nullptr) {
7158 69 server_ext =
7159
1/4
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
69 static_cast<NET_SERVER *>(MYSQL_EXTENSION_PTR(mysql)->server_extn);
7160 69 net->extension = server_ext;
7161 }
7162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
69 assert(server_ext != nullptr);
7163
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 mysql_compress_context_init(&server_ext->compress_ctx, algorithm,
7164 compress_level);
7165 #endif
7166 }
7167 #ifdef CHECK_LICENSE
7168 if (check_license(mysql)) return STATE_MACHINE_FAILED;
7169 #endif
7170
7171 #ifdef MYSQL_SERVER
7172 10167 return STATE_MACHINE_DONE;
7173 #else
7174 156467 ctx->state_function = csm_prep_init_commands;
7175 #endif
7176
7177 156466 return STATE_MACHINE_CONTINUE;
7178 166634 }
7179
7180 #ifndef MYSQL_SERVER
7181 /**
7182 Prepare to send a sequence of init commands.
7183 */
7184 156465 static mysql_state_machine_status csm_prep_init_commands(
7185 mysql_async_connect *ctx) {
7186
1/2
✓ Branch 0 taken 156467 times.
✗ Branch 1 not taken.
156465 DBUG_TRACE;
7187 156467 MYSQL *mysql = ctx->mysql;
7188
2/2
✓ Branch 0 taken 156464 times.
✓ Branch 1 taken 3 times.
156467 if (!mysql->options.init_commands) {
7189 156464 return STATE_MACHINE_DONE;
7190 }
7191
7192 3 ctx->saved_reconnect = mysql->reconnect;
7193 3 mysql->reconnect = false;
7194
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 ctx->current_init_command = mysql->options.init_commands->begin();
7195
7196 3 ctx->state_function = csm_send_one_init_command;
7197 3 return STATE_MACHINE_CONTINUE;
7198 156467 }
7199
7200 /**
7201 Send an init command. This is called once per init command until
7202 they've all been run (or a failure occurs).
7203 */
7204 3 static mysql_state_machine_status csm_send_one_init_command(
7205 mysql_async_connect *ctx) {
7206
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_TRACE;
7207 3 MYSQL *mysql = ctx->mysql;
7208
7209
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mysql_real_query(mysql, *ctx->current_init_command,
7210
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 (ulong)strlen(*ctx->current_init_command)))
7211 return STATE_MACHINE_FAILED;
7212 int status;
7213 do {
7214
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if (mysql->fields) {
7215 MYSQL_RES *res;
7216
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (!(res = cli_use_result(mysql))) return STATE_MACHINE_FAILED;
7217
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mysql_free_result(res);
7218 }
7219
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if ((status = mysql_next_result(mysql)) > 0) return STATE_MACHINE_FAILED;
7220
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } while (status == 0);
7221
7222 3 ++ctx->current_init_command;
7223
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (ctx->current_init_command < mysql->options.init_commands->end()) {
7224 return STATE_MACHINE_CONTINUE;
7225 }
7226 3 mysql->reconnect = ctx->saved_reconnect;
7227
3/8
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 DBUG_PRINT("exit", ("Mysql handler: %p", mysql));
7228 3 return STATE_MACHINE_DONE;
7229 3 }
7230 #endif
7231
7232 316862 bool mysql_reconnect(MYSQL *mysql) {
7233 MYSQL tmp_mysql;
7234
1/2
✓ Branch 0 taken 316862 times.
✗ Branch 1 not taken.
316862 DBUG_TRACE;
7235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 316862 times.
316862 assert(mysql);
7236
3/8
✓ Branch 0 taken 316862 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 316862 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 316862 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
316862 DBUG_PRINT("enter", ("mysql->reconnect: %d", mysql->reconnect));
7237
7238
3/4
✓ Branch 0 taken 316616 times.
✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 316616 times.
316862 if ((mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info) {
7239 /* Allow reconnect next time */
7240 246 mysql->server_status &= ~SERVER_STATUS_IN_TRANS;
7241
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 234 times.
246 if (mysql->net.last_errno == 0)
7242
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
7243 246 return true;
7244 }
7245
1/2
✓ Branch 0 taken 316616 times.
✗ Branch 1 not taken.
316616 mysql_init(&tmp_mysql);
7246
1/2
✓ Branch 0 taken 316616 times.
✗ Branch 1 not taken.
316616 mysql_close_free_options(&tmp_mysql);
7247 316616 tmp_mysql.options = mysql->options;
7248 316616 tmp_mysql.options.my_cnf_file = tmp_mysql.options.my_cnf_group = nullptr;
7249 #ifdef MYSQL_SERVER
7250
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
472 NET_SERVER *server_extn = MYSQL_EXTENSION_PTR(&tmp_mysql)->server_extn =
7251
2/6
✓ Branch 0 taken 472 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 472 times.
✗ Branch 5 not taken.
472 MYSQL_EXTENSION_PTR(mysql)->server_extn;
7252
1/4
✓ Branch 0 taken 472 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
472 MYSQL_EXTENSION_PTR(mysql)->server_extn = nullptr;
7253 #endif
7254
2/2
✓ Branch 0 taken 306745 times.
✓ Branch 1 taken 9871 times.
316616 if (!mysql_real_connect(&tmp_mysql, mysql->host, mysql->user, mysql->passwd,
7255 316616 mysql->db, mysql->port, mysql->unix_socket,
7256
1/2
✓ Branch 0 taken 316616 times.
✗ Branch 1 not taken.
316616 mysql->client_flag | CLIENT_REMEMBER_OPTIONS)) {
7257 #ifdef MYSQL_SERVER
7258
1/4
✓ Branch 0 taken 173 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
173 MYSQL_EXTENSION_PTR(mysql)->server_extn = server_extn;
7259 #endif
7260 306745 memset(&tmp_mysql.options, 0, sizeof(tmp_mysql.options));
7261 306745 mysql->net.last_errno = tmp_mysql.net.last_errno;
7262 306745 my_stpcpy(mysql->net.last_error, tmp_mysql.net.last_error);
7263 306745 my_stpcpy(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
7264 306745 return true;
7265 }
7266
2/4
✓ Branch 0 taken 9871 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9871 times.
9871 if (mysql_set_character_set(&tmp_mysql, mysql->charset->csname)) {
7267 DBUG_PRINT("error", ("mysql_set_character_set() failed"));
7268 #ifdef MYSQL_SERVER
7269 MYSQL_EXTENSION_PTR(mysql)->server_extn = server_extn;
7270 #endif
7271 memset(&tmp_mysql.options, 0, sizeof(tmp_mysql.options));
7272 mysql_close(&tmp_mysql);
7273 mysql->net.last_errno = tmp_mysql.net.last_errno;
7274 my_stpcpy(mysql->net.last_error, tmp_mysql.net.last_error);
7275 my_stpcpy(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
7276 return true;
7277 }
7278
7279
3/8
✓ Branch 0 taken 9871 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9871 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9871 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
9871 DBUG_PRINT("info", ("reconnect succeded"));
7280 9871 tmp_mysql.reconnect = true;
7281 9871 tmp_mysql.free_me = mysql->free_me;
7282
7283 /* Move prepared statements (if any) over to the new mysql object */
7284 9871 tmp_mysql.stmts = mysql->stmts;
7285 9871 mysql->stmts = nullptr;
7286
7287 /* Don't free options as these are now used in tmp_mysql */
7288 9871 memset(&mysql->options, 0, sizeof(mysql->options));
7289 9871 mysql->free_me = false;
7290
1/2
✓ Branch 0 taken 9871 times.
✗ Branch 1 not taken.
9871 mysql_close(mysql);
7291 9871 *mysql = std::move(tmp_mysql);
7292
1/2
✓ Branch 0 taken 9871 times.
✗ Branch 1 not taken.
9871 net_clear(&mysql->net, true);
7293 9871 mysql->affected_rows = ~(my_ulonglong)0;
7294 9871 return false;
7295 316862 }
7296
7297 /**
7298 Open a new replication stream.
7299
7300 Compose and send COM_BINLOG_DUMP[_GTID] command
7301 using information in the MYSQL_RPL structure.
7302
7303 Caller must set the following MYSQL_RPL's slots:
7304 file_name_length, file_name, start_positions, server_id, flags
7305 and in case of MYSQL_RPL_GTID: gtid_set_size, gtid_set
7306 or fix_gtid_set/fix_gtid_set_arg which is used to compose command packet.
7307
7308 Note: we treat NULL rpl->file_name as an empty string.
7309 If rpl->file_name_length is 0, strlen(rpl->file_name)
7310 will be called to set it.
7311 If rpl->fix_gtid_set is not NULL it will be called to fill
7312 packet gtid set data (rpl->gtid_set is ignored).
7313
7314 @param mysql Connection handle.
7315 @param rpl Replication stream information.
7316
7317 @retval -1 Error.
7318 @retval 0 Success.
7319 */
7320 7196 int STDCALL mysql_binlog_open(MYSQL *mysql, MYSQL_RPL *rpl) {
7321
1/2
✓ Branch 0 taken 7196 times.
✗ Branch 1 not taken.
7196 DBUG_TRACE;
7322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7196 times.
7196 assert(mysql);
7323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7196 times.
7196 assert(rpl);
7324
7325 enum enum_server_command command;
7326 7196 uchar *command_buffer = nullptr;
7327 7196 size_t command_size = 0;
7328
7329 /*
7330 No need to check mysql->net.vio here as
7331 it'll be checked in the simple_command().
7332 */
7333
7334
2/2
✓ Branch 0 taken 2245 times.
✓ Branch 1 taken 4951 times.
7196 if (!rpl->file_name) {
7335 2245 rpl->file_name = const_cast<char *>("");
7336 2245 rpl->file_name_length = 0;
7337
1/2
✓ Branch 0 taken 4951 times.
✗ Branch 1 not taken.
4951 } else if (rpl->file_name_length == 0)
7338 4951 rpl->file_name_length = strlen(rpl->file_name);
7339
7340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7196 times.
7196 if (rpl->file_name_length > UINT_MAX) {
7341 set_mysql_error(mysql, CR_FILE_NAME_TOO_LONG, unknown_sqlstate);
7342 return -1;
7343 }
7344
7345
2/2
✓ Branch 0 taken 2250 times.
✓ Branch 1 taken 4946 times.
7196 if (rpl->flags & MYSQL_RPL_GTID) {
7346 2250 command = COM_BINLOG_DUMP_GTID;
7347
7348 #define GTID_ENCODED_DATA_SIZE 8
7349
7350 4500 size_t alloc_size = rpl->file_name_length + ::BINLOG_FLAGS_INFO_SIZE +
7351 ::BINLOG_SERVER_ID_INFO_SIZE +
7352 ::BINLOG_NAME_SIZE_INFO_SIZE + ::BINLOG_POS_INFO_SIZE +
7353 2250 ::BINLOG_DATA_SIZE_INFO_SIZE +
7354
1/2
✓ Branch 0 taken 2250 times.
✗ Branch 1 not taken.
2250 (rpl->gtid_set_encoded_size ? rpl->gtid_set_encoded_size
7355 : GTID_ENCODED_DATA_SIZE) +
7356 1;
7357
7358
2/4
✓ Branch 0 taken 2250 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2250 times.
2250 if (!(command_buffer = (uchar *)my_malloc(PSI_NOT_INSTRUMENTED, alloc_size,
7359 MYF(MY_WME)))) {
7360 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
7361 return -1;
7362 }
7363
7364 2250 uchar *ptr = command_buffer;
7365
7366 2250 int2store(ptr, rpl->flags); // Note: we use low 16 bits
7367 2250 ptr += ::BINLOG_FLAGS_INFO_SIZE;
7368 2250 int4store(ptr, rpl->server_id);
7369 2250 ptr += ::BINLOG_SERVER_ID_INFO_SIZE;
7370 2250 int4store(ptr, static_cast<uint32>(rpl->file_name_length));
7371 2250 ptr += ::BINLOG_NAME_SIZE_INFO_SIZE;
7372 2250 memcpy(ptr, rpl->file_name, rpl->file_name_length);
7373 2250 ptr += rpl->file_name_length;
7374 2250 int8store(ptr, rpl->start_position);
7375 2250 ptr += ::BINLOG_POS_INFO_SIZE;
7376
1/2
✓ Branch 0 taken 2250 times.
✗ Branch 1 not taken.
2250 if (rpl->gtid_set_encoded_size) {
7377 2250 int4store(ptr, static_cast<uint32>(rpl->gtid_set_encoded_size));
7378 2250 ptr += ::BINLOG_DATA_SIZE_INFO_SIZE;
7379
1/2
✓ Branch 0 taken 2250 times.
✗ Branch 1 not taken.
2250 if (rpl->fix_gtid_set)
7380
1/2
✓ Branch 0 taken 2250 times.
✗ Branch 1 not taken.
2250 rpl->fix_gtid_set(rpl, ptr);
7381 else
7382 memcpy(ptr, rpl->gtid_set_arg, rpl->gtid_set_encoded_size);
7383 2250 ptr += rpl->gtid_set_encoded_size;
7384 } else {
7385 /* No GTID set data, store 0 as its length. */
7386 int4store(ptr, static_cast<uint32>(GTID_ENCODED_DATA_SIZE));
7387 ptr += ::BINLOG_DATA_SIZE_INFO_SIZE;
7388 int8store(ptr, static_cast<uint64>(0));
7389 ptr += GTID_ENCODED_DATA_SIZE;
7390 }
7391
7392 2250 command_size = ptr - command_buffer;
7393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2250 times.
2250 assert(command_size == (alloc_size - 1));
7394 } else {
7395 4946 command = COM_BINLOG_DUMP;
7396 4946 size_t alloc_size = rpl->file_name_length + ::BINLOG_POS_OLD_INFO_SIZE +
7397 ::BINLOG_FLAGS_INFO_SIZE +
7398 ::BINLOG_SERVER_ID_INFO_SIZE + 1;
7399
7400
2/4
✓ Branch 0 taken 4946 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4946 times.
4946 if (!(command_buffer = (uchar *)my_malloc(PSI_NOT_INSTRUMENTED, alloc_size,
7401 MYF(MY_WME)))) {
7402 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
7403 return -1;
7404 }
7405
7406 4946 uchar *ptr = command_buffer;
7407
7408 /*
7409 COM_BINLOG_DUMP accepts only 4 bytes for the position, so
7410 we are forced to cast to uint32.
7411 */
7412 4946 int4store(ptr, (uint32)rpl->start_position);
7413 4946 ptr += ::BINLOG_POS_OLD_INFO_SIZE;
7414 4946 int2store(ptr, rpl->flags); // note: we use low 16 bits
7415 4946 ptr += ::BINLOG_FLAGS_INFO_SIZE;
7416 4946 int4store(ptr, rpl->server_id);
7417 4946 ptr += ::BINLOG_SERVER_ID_INFO_SIZE;
7418 4946 memcpy(ptr, rpl->file_name, rpl->file_name_length);
7419 4946 ptr += rpl->file_name_length;
7420
7421 4946 command_size = ptr - command_buffer;
7422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4946 times.
4946 assert(command_size == (alloc_size - 1));
7423 }
7424
7425
3/8
✓ Branch 0 taken 7196 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7196 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 7196 times.
7196 if (simple_command(mysql, command, command_buffer, command_size, 1)) {
7426 my_free(command_buffer);
7427 return -1;
7428 }
7429
7430
1/2
✓ Branch 0 taken 7196 times.
✗ Branch 1 not taken.
7196 my_free(command_buffer);
7431
7432 7196 return 0;
7433 7196 }
7434
7435 /**
7436 Fetch one event from the server.
7437
7438 Read one packet and check its validity,
7439 set rpl->buffer and rpl->size accordingly.
7440
7441 @param mysql Connection handle.
7442 @param rpl Replication stream information.
7443
7444 @retval -1 Got error packet.
7445 @retval 0 Success.
7446 */
7447 1363527 int STDCALL mysql_binlog_fetch(MYSQL *mysql, MYSQL_RPL *rpl) {
7448
1/2
✓ Branch 0 taken 1363527 times.
✗ Branch 1 not taken.
1363527 DBUG_TRACE;
7449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1363527 times.
1363527 assert(mysql);
7450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1363527 times.
1363527 assert(rpl);
7451
7452 for (;;) {
7453 /* Read a packet from the server. */
7454
1/2
✓ Branch 0 taken 1363381 times.
✗ Branch 1 not taken.
1363527 ulong packet_len = cli_safe_read(mysql, nullptr);
7455
7456 1363381 NET *net = &mysql->net;
7457
7458 /* Check if error packet. */
7459
3/4
✓ Branch 0 taken 1356764 times.
✓ Branch 1 taken 6617 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1356764 times.
1363381 if (packet_len == packet_error || packet_len == 0) {
7460 6617 return -1;
7461 }
7462 /* Check if EOF packet. */
7463
3/4
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 1356677 times.
✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
1356764 else if (packet_len < 8 && net->read_pos[0] == 254) {
7464 87 rpl->size = 0;
7465 87 return 0;
7466 }
7467
7468 /* Normal packet. */
7469
2/2
✓ Branch 0 taken 14110 times.
✓ Branch 1 taken 1342567 times.
1356677 if (rpl->flags & MYSQL_RPL_SKIP_HEARTBEAT) {
7470 14110 Log_event_type event_type =
7471 14110 (Log_event_type)net->read_pos[1 + EVENT_TYPE_OFFSET];
7472
2/4
✓ Branch 0 taken 14110 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14110 times.
14110 if ((event_type == binary_log::HEARTBEAT_LOG_EVENT) ||
7473 (event_type == binary_log::HEARTBEAT_LOG_EVENT_V2))
7474 continue;
7475 }
7476
7477 1356677 rpl->buffer = net->read_pos;
7478 1356677 rpl->size = packet_len;
7479 1356677 return 0;
7480 }
7481 1363381 }
7482
7483 /**
7484 Close replication stream.
7485
7486 @param mysql Connection handle.
7487 @param rpl Replication stream information.
7488 */
7489 27 void STDCALL mysql_binlog_close(MYSQL *mysql, MYSQL_RPL *rpl) {
7490
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 DBUG_TRACE;
7491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 assert(mysql);
7492
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 assert(rpl);
7493
7494
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 end_server(mysql);
7495
7496 27 rpl->buffer = nullptr;
7497 27 rpl->size = 0;
7498 27 }
7499
7500 /**************************************************************************
7501 Set current database
7502 **************************************************************************/
7503
7504 2519 int STDCALL mysql_select_db(MYSQL *mysql, const char *db) {
7505 int error;
7506
1/2
✓ Branch 0 taken 2519 times.
✗ Branch 1 not taken.
2519 DBUG_TRACE;
7507
3/8
✓ Branch 0 taken 2519 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2519 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2519 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2519 DBUG_PRINT("enter", ("db: '%s'", db));
7508
7509
4/8
✓ Branch 0 taken 2519 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2519 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 15 times.
✓ Branch 7 taken 2504 times.
2519 if ((error = simple_command(mysql, COM_INIT_DB, (const uchar *)db,
7510 (ulong)strlen(db), 0)))
7511 15 return error;
7512
1/2
✓ Branch 0 taken 2504 times.
✗ Branch 1 not taken.
2504 my_free(mysql->db);
7513
1/2
✓ Branch 0 taken 2504 times.
✗ Branch 1 not taken.
2504 mysql->db = my_strdup(key_memory_MYSQL, db, MYF(MY_WME));
7514 2504 return 0;
7515 2519 }
7516
7517 /*************************************************************************
7518 Send a QUIT to the server and close the connection
7519 If handle is allocated by mysql connect free it.
7520 *************************************************************************/
7521
7522 517198 void mysql_close_free_options(MYSQL *mysql) {
7523
1/2
✓ Branch 0 taken 517246 times.
✗ Branch 1 not taken.
517198 DBUG_TRACE;
7524
7525
1/2
✓ Branch 0 taken 517224 times.
✗ Branch 1 not taken.
517246 my_free(mysql->options.user);
7526
1/2
✓ Branch 0 taken 517225 times.
✗ Branch 1 not taken.
517224 my_free(mysql->options.host);
7527
1/2
✓ Branch 0 taken 517229 times.
✗ Branch 1 not taken.
517225 my_free(mysql->options.password);
7528
1/2
✓ Branch 0 taken 517227 times.
✗ Branch 1 not taken.
517229 my_free(mysql->options.unix_socket);
7529
1/2
✓ Branch 0 taken 517227 times.
✗ Branch 1 not taken.
517227 my_free(mysql->options.db);
7530
1/2
✓ Branch 0 taken 517220 times.
✗ Branch 1 not taken.
517227 my_free(mysql->options.my_cnf_file);
7531
1/2
✓ Branch 0 taken 517219 times.
✗ Branch 1 not taken.
517220 my_free(mysql->options.my_cnf_group);
7532
1/2
✓ Branch 0 taken 517210 times.
✗ Branch 1 not taken.
517219 my_free(mysql->options.charset_dir);
7533
1/2
✓ Branch 0 taken 517230 times.
✗ Branch 1 not taken.
517210 my_free(mysql->options.charset_name);
7534
1/2
✓ Branch 0 taken 517222 times.
✗ Branch 1 not taken.
517230 my_free(mysql->options.bind_address);
7535
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 517218 times.
517222 if (mysql->options.init_commands) {
7536
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 char **ptr = mysql->options.init_commands->begin();
7537
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 char **end = mysql->options.init_commands->end();
7538
3/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
8 for (; ptr < end; ptr++) my_free(*ptr);
7539 4 mysql->options.init_commands->~Init_commands_array();
7540
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 my_free(mysql->options.init_commands);
7541 }
7542
1/2
✓ Branch 0 taken 517224 times.
✗ Branch 1 not taken.
517222 mysql_ssl_free(mysql);
7543 #if defined(_WIN32)
7544 my_free(mysql->options.shared_memory_base_name);
7545 #endif /* _WIN32 */
7546
2/2
✓ Branch 0 taken 477544 times.
✓ Branch 1 taken 39680 times.
517224 if (mysql->options.extension) {
7547
1/2
✓ Branch 0 taken 477556 times.
✗ Branch 1 not taken.
477544 my_free(mysql->options.extension->plugin_dir);
7548
1/2
✓ Branch 0 taken 477547 times.
✗ Branch 1 not taken.
477556 my_free(mysql->options.extension->default_auth);
7549
1/2
✓ Branch 0 taken 477542 times.
✗ Branch 1 not taken.
477547 my_free(mysql->options.extension->server_public_key_path);
7550
2/2
✓ Branch 0 taken 160539 times.
✓ Branch 1 taken 317003 times.
477542 delete mysql->options.extension->connection_attributes;
7551
1/2
✓ Branch 0 taken 477491 times.
✗ Branch 1 not taken.
477497 my_free(mysql->options.extension->compression_algorithm);
7552
1/2
✓ Branch 0 taken 477486 times.
✗ Branch 1 not taken.
477491 my_free(mysql->options.extension->ssl_session_data);
7553
1/2
✓ Branch 0 taken 477486 times.
✗ Branch 1 not taken.
477486 my_free(mysql->options.extension);
7554 }
7555 517166 memset(&mysql->options, 0, sizeof(mysql->options));
7556 517166 }
7557
7558 /*
7559 Free all memory allocated in a MYSQL handle but preserve
7560 current options if any.
7561 */
7562
7563 606437 void mysql_close_free(MYSQL *mysql) {
7564 606437 my_free(mysql->host_info);
7565 606459 my_free(mysql->user);
7566 606459 my_free(mysql->passwd);
7567 606455 my_free(mysql->db);
7568
7569 /* Free extension if any */
7570
2/2
✓ Branch 0 taken 477966 times.
✓ Branch 1 taken 128496 times.
606462 if (mysql->extension)
7571 477966 mysql_extension_free(static_cast<MYSQL_EXTENSION *>(mysql->extension));
7572
7573 606463 my_free(mysql->field_alloc);
7574
7575
2/2
✓ Branch 0 taken 18617 times.
✓ Branch 1 taken 587844 times.
606461 if (mysql->connector_fd)
7576 18617 free_vio_ssl_acceptor_fd(
7577 18617 reinterpret_cast<st_VioSSLFd *>(mysql->connector_fd));
7578 606461 mysql->connector_fd = nullptr;
7579
7580 606461 mysql->field_alloc = nullptr;
7581
7582 /* Clear pointers for better safety */
7583 606461 mysql->host_info = nullptr;
7584 606461 mysql->user = nullptr;
7585 606461 mysql->passwd = nullptr;
7586 606461 mysql->db = nullptr;
7587 606461 mysql->extension = nullptr;
7588 606461 }
7589
7590 /**
7591 For use when the connection to the server has been lost (in which case
7592 the server has discarded all information about prepared statements
7593 associated with the connection).
7594
7595 Mark all statements in mysql->stmts by setting stmt->mysql= 0 if the
7596 statement has transitioned beyond the MYSQL_STMT_INIT_DONE state, and
7597 unlink the statement from the mysql->stmts list.
7598
7599 The remaining pruned list of statements (if any) is kept in mysql->stmts.
7600
7601 @param mysql pointer to the MYSQL object
7602 */
7603 234956 static void mysql_prune_stmt_list(MYSQL *mysql) {
7604 234956 LIST *pruned_list = nullptr;
7605
7606
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 234968 times.
234973 while (mysql->stmts) {
7607 5 LIST *element = mysql->stmts;
7608 MYSQL_STMT *stmt;
7609
7610 5 mysql->stmts = list_delete(element, element);
7611 5 stmt = (MYSQL_STMT *)element->data;
7612
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 if (stmt->state != MYSQL_STMT_INIT_DONE) {
7613 3 stmt->mysql = nullptr;
7614 3 stmt->last_errno = CR_SERVER_LOST;
7615 3 my_stpcpy(stmt->last_error, ER_CLIENT(CR_SERVER_LOST));
7616 3 my_stpcpy(stmt->sqlstate, unknown_sqlstate);
7617 } else {
7618 2 pruned_list = list_add(pruned_list, element);
7619 }
7620 }
7621
7622 234968 mysql->stmts = pruned_list;
7623 234968 }
7624
7625 /*
7626 Clear connection pointer of every statement: this is necessary
7627 to give error on attempt to use a prepared statement of closed
7628 connection.
7629
7630 SYNOPSIS
7631 mysql_detach_stmt_list()
7632 stmt_list pointer to mysql->stmts
7633 func_name name of calling function
7634
7635 NOTE
7636 There is similar code in mysql_reconnect(), so changes here
7637 should also be reflected there.
7638 */
7639
7640 198839 void mysql_detach_stmt_list(LIST **stmt_list [[maybe_unused]],
7641 const char *func_name [[maybe_unused]]) {
7642 #ifndef MYSQL_SERVER
7643 /* Reset connection handle in all prepared statements. */
7644 188486 LIST *element = *stmt_list;
7645 char buff[MYSQL_ERRMSG_SIZE];
7646
1/2
✓ Branch 0 taken 188514 times.
✗ Branch 1 not taken.
188486 DBUG_TRACE;
7647
7648 188514 snprintf(buff, sizeof(buff) - 1, ER_CLIENT(CR_STMT_CLOSED), func_name);
7649
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 188511 times.
188514 for (; element; element = element->next) {
7650 3 MYSQL_STMT *stmt = (MYSQL_STMT *)element->data;
7651
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 set_stmt_error(stmt, CR_STMT_CLOSED, unknown_sqlstate, buff);
7652 3 stmt->mysql = nullptr;
7653 /* No need to call list_delete for statement here */
7654 }
7655 188511 *stmt_list = nullptr;
7656 377012 return;
7657 #endif /* !MYSQL_SERVER */
7658 198864 }
7659
7660 198630 void STDCALL mysql_close(MYSQL *mysql) {
7661
1/2
✓ Branch 0 taken 198706 times.
✗ Branch 1 not taken.
198630 DBUG_TRACE;
7662
2/2
✓ Branch 0 taken 198571 times.
✓ Branch 1 taken 135 times.
198706 if (mysql) /* Some simple safety */
7663 {
7664 /* If connection is still up, send a QUIT message */
7665
2/2
✓ Branch 0 taken 148769 times.
✓ Branch 1 taken 49802 times.
198571 if (mysql->net.vio != nullptr &&
7666
2/2
✓ Branch 0 taken 148768 times.
✓ Branch 1 taken 1 times.
148769 mysql->net.last_errno != NET_ERROR_SOCKET_UNUSABLE &&
7667
1/2
✓ Branch 0 taken 148769 times.
✗ Branch 1 not taken.
148768 mysql->net.last_errno != NET_ERROR_SOCKET_NOT_WRITABLE) {
7668
1/2
✓ Branch 0 taken 148765 times.
✗ Branch 1 not taken.
148769 free_old_query(mysql);
7669 148765 mysql->status = MYSQL_STATUS_READY; /* Force command */
7670 148765 bool old_reconnect = mysql->reconnect;
7671 148765 mysql->reconnect = false; // avoid recursion
7672
3/4
✓ Branch 0 taken 148768 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 148284 times.
✓ Branch 3 taken 484 times.
148765 if (vio_is_blocking(mysql->net.vio)) {
7673
3/6
✓ Branch 0 taken 148271 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 148287 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
148284 simple_command(mysql, COM_QUIT, (uchar *)nullptr, 0, 1);
7674 } else {
7675 /*
7676 Best effort; try to toss a command on the wire, but we can't wait
7677 to hear back.
7678 */
7679 bool err; /* unused */
7680
1/2
✓ Branch 0 taken 483 times.
✗ Branch 1 not taken.
484 simple_command_nonblocking(mysql, COM_QUIT, (uchar *)nullptr, 0, 1,
7681 &err);
7682 }
7683 148770 mysql->reconnect = old_reconnect;
7684
1/2
✓ Branch 0 taken 148762 times.
✗ Branch 1 not taken.
148770 end_server(mysql); /* Sets mysql->net.vio= 0 */
7685 }
7686
1/2
✓ Branch 0 taken 198566 times.
✗ Branch 1 not taken.
198564 mysql_close_free(mysql);
7687
1/2
✓ Branch 0 taken 198571 times.
✗ Branch 1 not taken.
198566 mysql_close_free_options(mysql);
7688
1/2
✓ Branch 0 taken 198566 times.
✗ Branch 1 not taken.
198571 mysql_detach_stmt_list(&mysql->stmts, "mysql_close");
7689
2/2
✓ Branch 0 taken 22990 times.
✓ Branch 1 taken 175576 times.
198566 if (mysql->free_me) {
7690
1/2
✓ Branch 0 taken 23004 times.
✗ Branch 1 not taken.
22990 my_free(mysql);
7691 }
7692 }
7693 198715 }
7694
7695 12869555 static bool cli_read_query_result(MYSQL *mysql) {
7696 uchar *pos;
7697 ulong field_count;
7698 ulong length;
7699
1/2
✓ Branch 0 taken 12869563 times.
✗ Branch 1 not taken.
12869555 DBUG_TRACE;
7700
7701
3/4
✓ Branch 0 taken 12869469 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 89095 times.
✓ Branch 3 taken 12780374 times.
12869563 if ((length = cli_safe_read(mysql, nullptr)) == packet_error) return true;
7702
1/2
✓ Branch 0 taken 12780465 times.
✗ Branch 1 not taken.
12780374 free_old_query(mysql); /* Free old result */
7703 #ifndef MYSQL_SERVER /* Avoid warn of unused labels*/
7704 12722045 get_info:
7705 #endif
7706 12781701 pos = (uchar *)mysql->net.read_pos;
7707
3/4
✓ Branch 0 taken 12781627 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3741848 times.
✓ Branch 3 taken 9039779 times.
12781701 if ((field_count = net_field_length(&pos)) == 0) {
7708
1/2
✓ Branch 0 taken 3741761 times.
✗ Branch 1 not taken.
3741848 read_ok_ex(mysql, length);
7709 #if defined(CLIENT_PROTOCOL_TRACING)
7710
2/2
✓ Branch 0 taken 80955 times.
✓ Branch 1 taken 3638535 times.
3719490 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
7711
2/10
✓ Branch 0 taken 80955 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 80955 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
80955 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
7712 else
7713
3/10
✓ Branch 0 taken 3638531 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3638531 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
3638535 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
7714 #endif
7715 3741757 return false;
7716 }
7717 #ifndef MYSQL_SERVER
7718
2/2
✓ Branch 0 taken 1244 times.
✓ Branch 1 taken 9001150 times.
9002394 if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
7719 {
7720 int error;
7721
7722
2/10
✓ Branch 0 taken 1244 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1244 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1244 MYSQL_TRACE_STAGE(mysql, FILE_REQUEST);
7723
7724
1/2
✓ Branch 0 taken 1244 times.
✗ Branch 1 not taken.
1244 error = handle_local_infile(mysql, (char *)pos);
7725
7726
2/10
✓ Branch 0 taken 1244 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1244 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1244 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
7727
7728
7/8
✓ Branch 0 taken 1244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1242 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 1236 times.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 1236 times.
1244 if ((length = cli_safe_read(mysql, nullptr)) == packet_error || error)
7729 8 return true;
7730 1236 goto get_info; /* Get info packet */
7731 }
7732 #endif
7733
2/2
✓ Branch 0 taken 74023 times.
✓ Branch 1 taken 8964512 times.
9038535 if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
7734 74023 mysql->server_status |= SERVER_STATUS_IN_TRANS;
7735
7736
2/4
✓ Branch 0 taken 9038543 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9038543 times.
9038535 if (read_com_query_metadata(mysql, pos, field_count)) return true;
7737
7738 9038543 mysql->status = MYSQL_STATUS_GET_RESULT;
7739 9038543 mysql->field_count = (uint)field_count;
7740
7741
2/10
✓ Branch 0 taken 9001158 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9001158 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
9001158 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_ROW);
7742
7743
3/8
✓ Branch 0 taken 9038544 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9038544 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9038544 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
9038543 DBUG_PRINT("exit", ("ok"));
7744 9038544 return false;
7745 12869404 }
7746 30486374 static net_async_status cli_read_query_result_nonblocking(MYSQL *mysql) {
7747
1/2
✓ Branch 0 taken 30486374 times.
✗ Branch 1 not taken.
30486374 DBUG_TRACE;
7748 30486374 NET *net = &mysql->net;
7749
1/2
✓ Branch 0 taken 30486374 times.
✗ Branch 1 not taken.
30486374 NET_ASYNC *net_async = NET_ASYNC_DATA(net);
7750
2/6
✓ Branch 0 taken 30486374 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30486374 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
30486374 MYSQL_ASYNC *async_context = ASYNC_DATA(mysql);
7751 30486374 uchar *pos = nullptr;
7752 ulong field_count;
7753 ulong length;
7754
7755
2/2
✓ Branch 0 taken 157 times.
✓ Branch 1 taken 30486217 times.
30486374 if (net_async->async_read_query_result_status ==
7756 NET_ASYNC_READ_QUERY_RESULT_IDLE) {
7757 157 net_async->async_read_query_result_status =
7758 NET_ASYNC_READ_QUERY_RESULT_FIELD_COUNT;
7759 }
7760
7761
1/2
✓ Branch 0 taken 30486374 times.
✗ Branch 1 not taken.
30486374 if (net_async->async_read_query_result_status ==
7762 NET_ASYNC_READ_QUERY_RESULT_FIELD_COUNT) {
7763 net_async_status status =
7764
1/2
✓ Branch 0 taken 30486374 times.
✗ Branch 1 not taken.
30486374 cli_safe_read_nonblocking(mysql, nullptr, &length);
7765
2/2
✓ Branch 0 taken 30486217 times.
✓ Branch 1 taken 157 times.
30486374 if (status == NET_ASYNC_NOT_READY) {
7766 30486217 return NET_ASYNC_NOT_READY;
7767 }
7768
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 157 times.
157 if (length == packet_error) {
7769 if (NET_ASYNC_DATA(net) != nullptr)
7770 net_async->async_read_query_result_status =
7771 NET_ASYNC_READ_QUERY_RESULT_IDLE;
7772 async_context->async_op_status = ASYNC_OP_UNSET;
7773 async_context->async_query_state = QUERY_IDLE;
7774 async_context->async_query_length = 0;
7775 return NET_ASYNC_ERROR;
7776 }
7777 157 mysql->packet_length = length;
7778
7779
1/2
✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
157 free_old_query(mysql); /* Free old result */
7780 #ifndef MYSQL_SERVER /* Avoid warn of unused labels*/
7781 157 get_info:
7782 #endif
7783 157 pos = (uchar *)mysql->net.read_pos;
7784
3/4
✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 122 times.
157 if ((field_count = net_field_length(&pos)) == 0) {
7785
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 read_ok_ex(mysql, length);
7786 #if defined(CLIENT_PROTOCOL_TRACING)
7787
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 24 times.
35 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
7788
2/10
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
11 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
7789 else
7790
2/10
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
24 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
7791 #endif
7792 35 net_async->async_read_query_result_status =
7793 NET_ASYNC_READ_QUERY_RESULT_IDLE;
7794 35 async_context->async_op_status = ASYNC_OP_UNSET;
7795 35 async_context->async_query_state = QUERY_IDLE;
7796 35 async_context->async_query_length = 0;
7797 35 return NET_ASYNC_COMPLETE;
7798 }
7799 #ifndef MYSQL_SERVER
7800
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
7801 {
7802 int error;
7803
7804 MYSQL_TRACE_STAGE(mysql, FILE_REQUEST);
7805
7806 if (!(mysql->options.client_flag & CLIENT_LOCAL_FILES)) {
7807 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
7808 net_async->async_read_query_result_status =
7809 NET_ASYNC_READ_QUERY_RESULT_IDLE;
7810 async_context->async_op_status = ASYNC_OP_UNSET;
7811 async_context->async_query_state = QUERY_IDLE;
7812 async_context->async_query_length = 0;
7813 return NET_ASYNC_ERROR;
7814 }
7815
7816 error = handle_local_infile(mysql, (char *)pos);
7817
7818 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
7819
7820 /* TODO: Make LOAD DATA LOCAL INFILE asynchronous. */
7821 if ((length = cli_safe_read(mysql, nullptr)) == packet_error || error) {
7822 /*
7823 When processing of LOAD DATA fails, server sends an error packet,
7824 which is handled here, for async connections.
7825 */
7826 if (NET_ASYNC_DATA(net) != nullptr)
7827 net_async->async_read_query_result_status =
7828 NET_ASYNC_READ_QUERY_RESULT_IDLE;
7829 async_context->async_op_status = ASYNC_OP_UNSET;
7830 async_context->async_query_state = QUERY_IDLE;
7831 async_context->async_query_length = 0;
7832 return NET_ASYNC_ERROR;
7833 }
7834 goto get_info; /* Get info packet */
7835 }
7836 #endif
7837
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
7838 mysql->server_status |= SERVER_STATUS_IN_TRANS;
7839
7840 122 mysql->field_count = (uint)field_count;
7841 122 net_async->async_read_query_result_status =
7842 NET_ASYNC_READ_QUERY_RESULT_FIELD_INFO;
7843 }
7844
7845
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (net_async->async_read_query_result_status ==
7846 NET_ASYNC_READ_QUERY_RESULT_FIELD_INFO) {
7847 int res;
7848 244 net_async_status status = read_com_query_metadata_nonblocking(
7849
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 mysql, pos, mysql->field_count, &res);
7850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (status == NET_ASYNC_NOT_READY) {
7851 return NET_ASYNC_NOT_READY;
7852 }
7853
7854
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (res) {
7855 net_async->async_read_query_result_status =
7856 NET_ASYNC_READ_QUERY_RESULT_IDLE;
7857 async_context->async_op_status = ASYNC_OP_UNSET;
7858 async_context->async_query_state = QUERY_IDLE;
7859 async_context->async_query_length = 0;
7860 return NET_ASYNC_ERROR;
7861 }
7862 }
7863
7864 122 mysql->status = MYSQL_STATUS_GET_RESULT;
7865
3/8
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 122 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 122 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
122 DBUG_PRINT("exit", ("ok, %u", mysql->field_count));
7866 122 net_async->async_read_query_result_status = NET_ASYNC_READ_QUERY_RESULT_IDLE;
7867 122 async_context->async_op_status = ASYNC_OP_UNSET;
7868 122 async_context->async_query_state = QUERY_IDLE;
7869 122 async_context->async_query_length = 0;
7870 122 return NET_ASYNC_COMPLETE;
7871 30486374 }
7872
7873 /**
7874 Helper function to serialize the parameters data.
7875
7876 @param mysql the mysql handle
7877 @param[out] pret_data out pointer to the data. set to nullptr if there's no
7878 data
7879 @param[out] pret_data_length length of the data in pred_data. 0 if there's no
7880 data
7881 @return operation status
7882 @retval non-zero failed
7883 @retval zero success. Check pret_*
7884 */
7885 12533415 static int mysql_prepare_com_query_parameters(MYSQL *mysql,
7886 unsigned char **pret_data,
7887 unsigned long *pret_data_length) {
7888
1/2
✓ Branch 0 taken 12533449 times.
✗ Branch 1 not taken.
12533415 DBUG_TRACE;
7889
1/4
✓ Branch 0 taken 12533449 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12533449 MYSQL_EXTENSION *ext = MYSQL_EXTENSION_PTR(mysql);
7890
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12533449 times.
12533449 assert(ext);
7891 12533449 bool send_named_params =
7892 12533449 (mysql->server_capabilities & CLIENT_QUERY_ATTRIBUTES) != 0;
7893 12533449 *pret_data = nullptr;
7894 12533449 *pret_data_length = 0;
7895
2/2
✓ Branch 0 taken 12495894 times.
✓ Branch 1 taken 37555 times.
12533449 if (send_named_params) {
7896 /*
7897 The state is checked later in cli_advanced_command too, but it's
7898 already too late since the below will reset the NET buffers.
7899 So we need to check before doing the below too.
7900 */
7901
2/2
✓ Branch 0 taken 12495889 times.
✓ Branch 1 taken 5 times.
12495894 if (mysql->status != MYSQL_STATUS_READY ||
7902
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 12495880 times.
12495889 mysql->server_status & SERVER_MORE_RESULTS_EXISTS) {
7903
3/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
14 DBUG_PRINT("error", ("state: %d", mysql->status));
7904
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
7905 4 return 1;
7906 }
7907
7908
2/2
✓ Branch 0 taken 450319 times.
✓ Branch 1 taken 12045561 times.
12495880 if (mysql->net.vio == nullptr) { /* Do reconnect if possible */
7909
2/2
✓ Branch 0 taken 138659 times.
✓ Branch 1 taken 311660 times.
450319 if (!mysql->reconnect) {
7910 /* If we don't have any vio there must be an error */
7911
2/2
✓ Branch 0 taken 414 times.
✓ Branch 1 taken 138245 times.
138659 if (mysql->net.last_errno == 0)
7912
1/2
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
414 set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
7913 138659 return 1;
7914 }
7915
3/4
✓ Branch 0 taken 311660 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 305964 times.
✓ Branch 3 taken 5696 times.
311660 if (mysql_reconnect(mysql)) return 1;
7916 /* mysql has a new ext at this point, take it again */
7917
1/4
✓ Branch 0 taken 5696 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
5696 ext = MYSQL_EXTENSION_PTR(mysql);
7918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5696 times.
5696 assert(ext);
7919 }
7920
7921
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12051261 times.
12051261 if (mysql_int_serialize_param_data(
7922 &mysql->net, ext->bind_info.n_params, ext->bind_info.bind,
7923
1/2
✓ Branch 0 taken 12051261 times.
✗ Branch 1 not taken.
12051257 const_cast<const char **>(ext->bind_info.names), 1, pret_data,
7924 pret_data_length, 1, true, true, true)) {
7925 set_mysql_error(mysql, mysql->net.last_errno, mysql->net.sqlstate);
7926 return 1;
7927 }
7928
3/6
✓ Branch 0 taken 12051256 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12051256 times.
12051261 assert(ext == MYSQL_EXTENSION_PTR(mysql));
7929
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12051256 times.
12051256 assert(ext);
7930
1/2
✓ Branch 0 taken 12051262 times.
✗ Branch 1 not taken.
12051256 mysql_extension_bind_free(ext);
7931 }
7932 12088817 return 0;
7933 12533444 }
7934 /*
7935 Send the query and return so we can do something else.
7936 Needs to be followed by mysql_read_query_result() when we want to
7937 finish processing it.
7938 */
7939
7940 12533271 int STDCALL mysql_send_query(MYSQL *mysql, const char *query, ulong length) {
7941
1/2
✓ Branch 0 taken 12533301 times.
✗ Branch 1 not taken.
12533271 DBUG_TRACE;
7942
7943 12533301 bool extension_was_present = (mysql->extension != nullptr);
7944
7945 STATE_INFO *info;
7946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12533301 times.
12533301 assert(mysql);
7947
7948
3/4
✓ Branch 0 taken 12532849 times.
✓ Branch 1 taken 452 times.
✓ Branch 2 taken 452 times.
✗ Branch 3 not taken.
12533301 MYSQL_EXTENSION *ext = MYSQL_EXTENSION_PTR(mysql);
7949
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12533301 times.
12533301 assert(ext);
7950
7951
7/10
✓ Branch 0 taken 12533299 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 12533298 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 12533293 times.
✓ Branch 7 taken 7 times.
✓ Branch 8 taken 12533275 times.
✗ Branch 9 not taken.
12533301 if ((info = STATE_DATA(mysql))) free_state_change_info(ext);
7952 uchar *ret_data;
7953 unsigned long ret_data_length;
7954 int retval =
7955
1/2
✓ Branch 0 taken 12533299 times.
✗ Branch 1 not taken.
12533282 mysql_prepare_com_query_parameters(mysql, &ret_data, &ret_data_length);
7956 /*
7957 mysql->extension is allocated memory inside mysql_init() before
7958 establishing a client-server connection. When MYSQL_EXTENSION_PTR() is
7959 called here in mysql_send_query() or in
7960 mysql_prepare_com_query_parameters() it allocates memory to
7961 mysql->extension if it is null (disconnected client). This memory is not
7962 freed later. When another query is executed mysql->extension is reallocated
7963 memory and this will cause a memory leak. To avoid this, mysql->extension
7964 is freed here if it was null when mysql_send_query was called and client is
7965 disconnected.
7966 */
7967
3/4
✓ Branch 0 taken 452 times.
✓ Branch 1 taken 12532847 times.
✓ Branch 2 taken 452 times.
✗ Branch 3 not taken.
12533299 if (!extension_was_present && !mysql->net.vio) {
7968
1/2
✓ Branch 0 taken 452 times.
✗ Branch 1 not taken.
452 mysql_extension_free(static_cast<MYSQL_EXTENSION *>(mysql->extension));
7969 452 mysql->extension = nullptr;
7970 }
7971
2/2
✓ Branch 0 taken 444627 times.
✓ Branch 1 taken 12088672 times.
12533299 if (retval) return 1;
7972
1/2
✓ Branch 0 taken 12088653 times.
✗ Branch 1 not taken.
12088672 int ret = (*mysql->methods->advanced_command)(
7973 mysql, COM_QUERY, ret_data, ret_data_length,
7974 12088653 pointer_cast<const uchar *>(query), length, true, nullptr);
7975
3/4
✓ Branch 0 taken 12051115 times.
✓ Branch 1 taken 37538 times.
✓ Branch 2 taken 12051130 times.
✗ Branch 3 not taken.
12088653 if (ret_data) my_free(ret_data);
7976 12088668 return ret;
7977 12533295 }
7978
7979 /**
7980 Executes the SQL statement pointed by query. This API is called by
7981 mysql_real_query_nonblocking to send query to server in asynchronous way.
7982
7983 @param[in] mysql connection handle
7984 @param[in] query query string to be executed
7985 @param[in] length length of query
7986
7987 @retval NET_ASYNC_ERROR query execution failed
7988 @retval NET_ASYNC_NOT_READY query not yet completed, call this API
7989 again
7990 @retval NET_ASYNC_COMPLETE query execution finished
7991 */
7992 6724 static net_async_status mysql_send_query_nonblocking_inner(MYSQL *mysql,
7993 const char *query,
7994 ulong length) {
7995
1/2
✓ Branch 0 taken 6724 times.
✗ Branch 1 not taken.
6724 DBUG_TRACE;
7996 STATE_INFO *info;
7997
7998
3/8
✓ Branch 0 taken 6724 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6724 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 6724 times.
✗ Branch 7 not taken.
6724 if ((info = STATE_DATA(mysql)))
7999
1/2
✓ Branch 0 taken 6724 times.
✗ Branch 1 not taken.
6724 free_state_change_info(static_cast<MYSQL_EXTENSION *>(mysql->extension));
8000
8001 bool ret;
8002
2/6
✓ Branch 0 taken 6724 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6724 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6724 MYSQL_ASYNC *async_context = ASYNC_DATA(mysql);
8003
8004 6724 if ((*mysql->methods->advanced_command_nonblocking)(
8005
1/2
✓ Branch 0 taken 6724 times.
✗ Branch 1 not taken.
6724 mysql, COM_QUERY, async_context->async_qp_data,
8006 async_context->async_qp_data_length,
8007 pointer_cast<const uchar *>(query), length, true, nullptr,
8008
2/2
✓ Branch 0 taken 6575 times.
✓ Branch 1 taken 149 times.
6724 &ret) == NET_ASYNC_NOT_READY) {
8009 6575 return NET_ASYNC_NOT_READY;
8010 }
8011
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 149 times.
149 if (ret)
8012 return NET_ASYNC_ERROR;
8013 else
8014 149 return NET_ASYNC_COMPLETE;
8015 6724 }
8016
8017 /**
8018 Wrapper around mysql_send_query_nonblocking_inner to be called externally
8019
8020 @param[in] mysql connection handle
8021 @param[in] query query string to be executed
8022 @param[in] length length of query
8023
8024 @retval NET_ASYNC_ERROR query execution failed
8025 @retval NET_ASYNC_NOT_READY query not yet completed, call this API again
8026 @retval NET_ASYNC_COMPLETE query execution finished
8027 */
8028 169 net_async_status STDCALL mysql_send_query_nonblocking(MYSQL *mysql,
8029 const char *query,
8030 ulong length) {
8031
1/2
✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
169 DBUG_TRACE;
8032
2/6
✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 169 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
169 MYSQL_ASYNC *async_context = ASYNC_DATA(mysql);
8033 169 net_async_status ret = NET_ASYNC_NOT_READY;
8034
3/8
✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 169 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 169 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
169 DBUG_PRINT("async", ("enter mysql_send_query_nonblocking state=%d",
8035 async_context->async_query_state));
8036
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 57 times.
169 if (async_context->async_query_state == QUERY_IDLE) {
8037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 assert(async_context->async_qp_data == nullptr);
8038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 assert(async_context->async_qp_data_length == 0);
8039
8040 112 async_context->async_query_length = length;
8041 112 async_context->async_query_state = QUERY_SENDING;
8042 112 async_context->async_op_status = ASYNC_OP_QUERY;
8043
3/8
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 112 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
112 DBUG_PRINT("async", ("set state=%d", async_context->async_query_state));
8044
8045
2/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 112 times.
112 if (mysql_prepare_com_query_parameters(
8046 mysql, &async_context->async_qp_data,
8047 &async_context->async_qp_data_length)) {
8048 set_query_idle(async_context);
8049 return NET_ASYNC_ERROR;
8050 }
8051 }
8052
8053
1/2
✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
169 ret = mysql_send_query_nonblocking_inner(mysql, query, length);
8054
8055
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 112 times.
169 if (ret == NET_ASYNC_NOT_READY)
8056 57 return ret;
8057
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 else if (ret == NET_ASYNC_ERROR) {
8058 set_query_idle(async_context);
8059 return ret;
8060 }
8061
8062 112 async_context->async_query_state = QUERY_READING_RESULT;
8063
3/8
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 112 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
112 DBUG_PRINT("async", ("set state=%d", async_context->async_query_state));
8064 /*
8065 Technically we don't need to keep the query attributes data until the
8066 state change as they're stored into the NET at the first call to
8067 advanced_command. But since advanced_command() requires these we
8068 keep them as they are.
8069 */
8070
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 free_async_qp_data(async_context);
8071 112 return ret;
8072 169 }
8073
8074 8414245 int STDCALL mysql_real_query(MYSQL *mysql, const char *query, ulong length) {
8075 int retval;
8076
1/2
✓ Branch 0 taken 8414281 times.
✗ Branch 1 not taken.
8414245 DBUG_TRACE;
8077
3/8
✓ Branch 0 taken 8414278 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8414270 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8414270 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
8414281 DBUG_PRINT("enter", ("handle: %p", mysql));
8078
3/8
✓ Branch 0 taken 8414262 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8414263 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8414263 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
8414270 DBUG_PRINT("query", ("Query = '%-.*s'", (int)length, query));
8079
4/6
✓ Branch 0 taken 8414259 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 8414254 times.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
8414263 DBUG_EXECUTE_IF("inject_ER_NET_READ_INTERRUPTED", {
8080 mysql->net.last_errno = ER_NET_READ_INTERRUPTED;
8081 DBUG_SET("-d,inject_ER_NET_READ_INTERRUPTED");
8082 return 1;
8083 });
8084
8085
3/4
✓ Branch 0 taken 8414273 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 138148 times.
✓ Branch 3 taken 8276125 times.
8414254 if (mysql_send_query(mysql, query, length)) return 1;
8086
1/2
✓ Branch 0 taken 8276019 times.
✗ Branch 1 not taken.
8276125 retval = (int)(*mysql->methods->read_query_result)(mysql);
8087
2/6
✓ Branch 0 taken 8276065 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8276081 times.
✗ Branch 5 not taken.
8276019 mysql_extension_bind_free(MYSQL_EXTENSION_PTR(mysql));
8088 8276081 return retval;
8089 8414234 }
8090
8091 /**
8092 Executes the SQL statement pointed by query. This sql statement length is set
8093 in length parameter. query string can contain multiple sql statements
8094 separated by semicolons. This function can return immediately with status set
8095 to NET_ASYNC_NOT_READY, in this case client application is expected to call
8096 this API until it returns NET_ASYNC_COMPLETE.
8097
8098 @param[in] mysql connection handle
8099 @param[in] query query string to be executed
8100 @param[in] length length of query
8101
8102 @retval NET_ASYNC_ERROR query execution failed
8103 @retval NET_ASYNC_NOT_READY query not yet completed, call this API again
8104 @retval NET_ASYNC_COMPLETE query execution finished
8105 */
8106 5961306 net_async_status STDCALL mysql_real_query_nonblocking(MYSQL *mysql,
8107 const char *query,
8108 ulong length) {
8109
1/2
✓ Branch 0 taken 5961306 times.
✗ Branch 1 not taken.
5961306 DBUG_TRACE;
8110
3/8
✓ Branch 0 taken 5961306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5961306 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5961306 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
5961306 DBUG_PRINT("enter", ("handle: %p", mysql));
8111
3/8
✓ Branch 0 taken 5961306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5961306 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5961306 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
5961306 DBUG_PRINT("query", ("Query = '%-.*s'", (int)length, query));
8112
2/6
✓ Branch 0 taken 5961306 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5961306 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
5961306 DBUG_EXECUTE_IF("inject_ER_NET_READ_INTERRUPTED", {
8113 mysql->net.last_errno = ER_NET_READ_INTERRUPTED;
8114 DBUG_SET("-d,inject_ER_NET_READ_INTERRUPTED");
8115 return NET_ASYNC_ERROR;
8116 });
8117
2/6
✓ Branch 0 taken 5961306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5961306 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
5961306 MYSQL_ASYNC *async_context = ASYNC_DATA(mysql);
8118
3/4
✓ Branch 0 taken 5961269 times.
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5961269 times.
5961306 assert(async_context->async_op_status == ASYNC_OP_UNSET ||
8119 async_context->async_op_status == ASYNC_OP_QUERY);
8120
8121 5961306 net_async_status status = NET_ASYNC_NOT_READY;
8122
3/8
✓ Branch 0 taken 5961306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5961306 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5961306 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
5961306 DBUG_PRINT("async", ("mysql_real_query_nonblocking start state=%d",
8123 async_context->async_query_state));
8124 /* 1st phase: send query. */
8125
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 5961269 times.
5961306 if (async_context->async_query_state == QUERY_IDLE) {
8126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 assert(async_context->async_qp_data == nullptr);
8127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 assert(async_context->async_qp_data_length == 0);
8128
2/4
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 37 times.
37 if (mysql_prepare_com_query_parameters(
8129 mysql, &async_context->async_qp_data,
8130 &async_context->async_qp_data_length)) {
8131 status = NET_ASYNC_ERROR;
8132 goto end;
8133 }
8134 37 async_context->async_query_length = length;
8135 37 async_context->async_op_status = ASYNC_OP_QUERY;
8136 37 async_context->async_query_state = QUERY_SENDING;
8137
3/8
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
37 DBUG_PRINT("async", ("set state=%d", async_context->async_query_state));
8138 }
8139
8140
2/2
✓ Branch 0 taken 6555 times.
✓ Branch 1 taken 5954751 times.
5961306 if (async_context->async_query_state == QUERY_SENDING) {
8141
1/2
✓ Branch 0 taken 6555 times.
✗ Branch 1 not taken.
6555 status = mysql_send_query_nonblocking_inner(mysql, query, length);
8142
2/2
✓ Branch 0 taken 6518 times.
✓ Branch 1 taken 37 times.
6555 if (status == NET_ASYNC_NOT_READY)
8143 6518 return NET_ASYNC_NOT_READY;
8144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 else if (status == NET_ASYNC_ERROR)
8145 goto end;
8146 37 async_context->async_query_state = QUERY_READING_RESULT;
8147
3/8
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
37 DBUG_PRINT("async", ("set state=%d", async_context->async_query_state));
8148 /*
8149 Technically we don't need to keep the query attributes data until the
8150 state change as they're stored into the NET at the first call to
8151 advanced_command. But since advanced_command() requires these we
8152 keep them as they are.
8153 */
8154
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 if (async_context->async_qp_data) {
8155
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 my_free(async_context->async_qp_data);
8156 37 async_context->async_qp_data = nullptr;
8157 37 async_context->async_qp_data_length = 0;
8158 }
8159 }
8160
8161 /* 2nd phase: read query result (field count, field info) */
8162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5954788 times.
5954788 if (async_context->async_query_state == QUERY_READING_RESULT) {
8163
1/2
✓ Branch 0 taken 5954788 times.
✗ Branch 1 not taken.
5954788 status = (*mysql->methods->read_query_result_nonblocking)(mysql);
8164
2/2
✓ Branch 0 taken 5954751 times.
✓ Branch 1 taken 37 times.
5954788 if (status == NET_ASYNC_NOT_READY)
8165 5954751 return NET_ASYNC_NOT_READY;
8166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 else if (status == NET_ASYNC_ERROR)
8167 goto end;
8168 }
8169
8170 end:
8171 37 async_context->async_op_status = ASYNC_OP_UNSET;
8172 37 async_context->async_query_state = QUERY_IDLE;
8173
3/8
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
37 DBUG_PRINT("async", ("set state=%d", async_context->async_query_state));
8174 37 async_context->async_query_length = 0;
8175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if (status == NET_ASYNC_ERROR)
8176 return NET_ASYNC_ERROR;
8177 else
8178 37 return NET_ASYNC_COMPLETE;
8179 5961306 }
8180
8181 /**************************************************************************
8182 Alloc result struct for buffered results. All rows are read to buffer.
8183 mysql_data_seek may be used.
8184 **************************************************************************/
8185
8186 9291684 MYSQL_RES *STDCALL mysql_store_result(MYSQL *mysql) {
8187 MYSQL_RES *result;
8188
1/2
✓ Branch 0 taken 9291686 times.
✗ Branch 1 not taken.
9291684 DBUG_TRACE;
8189
8190 /*
8191 Some queries (e.g. "CALL") may return an empty resultset.
8192 mysql->field_count is 0 in such cases.
8193 */
8194
2/2
✓ Branch 0 taken 328697 times.
✓ Branch 1 taken 8962989 times.
9291686 if (!mysql->field_count) return nullptr;
8195
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 8962982 times.
8962989 if (mysql->status != MYSQL_STATUS_GET_RESULT) {
8196
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
8197 7 return nullptr;
8198 }
8199 8962982 mysql->status = MYSQL_STATUS_READY; /* server is ready */
8200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8962981 times.
8962981 if (!(result = (MYSQL_RES *)my_malloc(
8201 key_memory_MYSQL_RES,
8202
1/2
✓ Branch 0 taken 8962981 times.
✗ Branch 1 not taken.
8962982 (uint)(sizeof(MYSQL_RES) + sizeof(ulong) * mysql->field_count),
8203 MYF(MY_WME | MY_ZEROFILL)))) {
8204 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
8205 return nullptr;
8206 }
8207
2/4
✓ Branch 0 taken 8962982 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8962982 times.
8962981 if (!(result->field_alloc = (MEM_ROOT *)my_malloc(
8208 key_memory_MYSQL, sizeof(MEM_ROOT), MYF(MY_WME | MY_ZEROFILL)))) {
8209 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
8210 my_free(result);
8211 return nullptr;
8212 }
8213 8962982 result->methods = mysql->methods;
8214 8962982 result->eof = true; /* Marker for buffered */
8215 8962982 result->lengths = (ulong *)(result + 1);
8216
3/4
✓ Branch 0 taken 8962981 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4120 times.
✓ Branch 3 taken 8958861 times.
8962982 if (!(result->data = (*mysql->methods->read_rows)(mysql, mysql->fields,
8217 mysql->field_count))) {
8218
1/2
✓ Branch 0 taken 4120 times.
✗ Branch 1 not taken.
4120 my_free(result->field_alloc);
8219
1/2
✓ Branch 0 taken 4120 times.
✗ Branch 1 not taken.
4120 my_free(result);
8220 4120 return nullptr;
8221 }
8222 8958861 mysql->affected_rows = result->row_count = result->data->rows;
8223 8958861 result->data_cursor = result->data->data;
8224 8958861 result->fields = mysql->fields;
8225 8958861 *result->field_alloc = std::move(*mysql->field_alloc);
8226 8958861 result->field_count = mysql->field_count;
8227 8958861 result->metadata = mysql->resultset_metadata;
8228 /* The rest of result members is zerofilled in my_malloc */
8229 8958861 mysql->fields = nullptr; /* fields is now in result */
8230 /* just in case this was mistakenly called after mysql_stmt_execute() */
8231 8958861 mysql->unbuffered_fetch_owner = nullptr;
8232 8958861 return result; /* Data fetched */
8233 9291685 }
8234
8235 /**
8236 This API reads all result set sent by server in an asynchronous way
8237
8238 @param[in] mysql connection handle
8239 @param[in] result buffer which holds all result sets.
8240
8241 @retval NET_ASYNC_NOT_READY reading of result sets not complete
8242 @retval NET_ASYNC_COMPLETE completed this asynchronous operation
8243 */
8244 enum net_async_status STDCALL
8245 250860 mysql_store_result_nonblocking(MYSQL *mysql, MYSQL_RES **result) {
8246
1/2
✓ Branch 0 taken 250860 times.
✗ Branch 1 not taken.
250860 DBUG_TRACE;
8247
2/6
✓ Branch 0 taken 250860 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 250860 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
250860 MYSQL_ASYNC *async_context = ASYNC_DATA(mysql);
8248 250860 *result = nullptr;
8249
8250 /*
8251 Some queries (e.g. "CALL") may return an empty resultset.
8252 mysql->field_count is 0 in such cases.
8253 */
8254
2/2
✓ Branch 0 taken 83585 times.
✓ Branch 1 taken 167275 times.
250860 if (!mysql->field_count) {
8255 83585 goto end;
8256 }
8257
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 167144 times.
167275 if (!async_context->async_store_result_result) {
8258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (mysql->status != MYSQL_STATUS_GET_RESULT) {
8259 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
8260 goto end;
8261 }
8262 131 mysql->status = MYSQL_STATUS_READY; /* server is ready */
8263
8264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (!(async_context->async_store_result_result = (MYSQL_RES *)my_malloc(
8265 key_memory_MYSQL_RES,
8266
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 (uint)(sizeof(MYSQL_RES) + sizeof(ulong) * mysql->field_count),
8267 MYF(MY_WME | MY_ZEROFILL)))) {
8268 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
8269 goto end;
8270 }
8271 262 if (!(async_context->async_store_result_result->field_alloc =
8272
2/4
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 131 times.
131 (MEM_ROOT *)my_malloc(key_memory_MYSQL, sizeof(MEM_ROOT),
8273 MYF(MY_WME | MY_ZEROFILL)))) {
8274 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
8275 my_free(async_context->async_store_result_result);
8276 goto end;
8277 }
8278 131 async_context->async_store_result_result->methods = mysql->methods;
8279 131 async_context->async_store_result_result->eof =
8280 true; /* Marker for buffered */
8281 131 async_context->async_store_result_result->lengths =
8282 131 (ulong *)(async_context->async_store_result_result + 1);
8283 }
8284
8285 334550 if ((*mysql->methods->read_rows_nonblocking)(
8286 mysql, mysql->fields, mysql->field_count,
8287
3/4
✓ Branch 0 taken 167275 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 167144 times.
✓ Branch 3 taken 131 times.
167275 &async_context->async_store_result_result->data) ==
8288 NET_ASYNC_NOT_READY) {
8289 167144 return NET_ASYNC_NOT_READY;
8290 }
8291
8292
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (!async_context->async_store_result_result->data) {
8293 my_free(async_context->async_store_result_result->field_alloc);
8294 my_free(async_context->async_store_result_result);
8295 goto end;
8296 }
8297 131 mysql->affected_rows = async_context->async_store_result_result->row_count =
8298 131 async_context->async_store_result_result->data->rows;
8299 131 async_context->async_store_result_result->data_cursor =
8300 131 async_context->async_store_result_result->data->data;
8301 131 async_context->async_store_result_result->fields = mysql->fields;
8302 131 *async_context->async_store_result_result->field_alloc =
8303 131 std::move(*mysql->field_alloc);
8304 131 async_context->async_store_result_result->field_count = mysql->field_count;
8305 131 async_context->async_store_result_result->metadata =
8306 131 mysql->resultset_metadata;
8307 /* The rest of result members is zerofilled in my_malloc */
8308 131 mysql->fields = nullptr; /* fields is now in result */
8309 /* just in case this was mistakenly called after mysql_stmt_execute() */
8310 131 mysql->unbuffered_fetch_owner = nullptr;
8311 131 *result = async_context->async_store_result_result;
8312 83716 end:
8313 83716 async_context->async_store_result_result = nullptr;
8314 83716 return NET_ASYNC_COMPLETE;
8315 250860 }
8316
8317 /**************************************************************************
8318 Alloc struct for use with unbuffered reads. Data is fetched by domand
8319 when calling to mysql_fetch_row.
8320 mysql_data_seek is a noop.
8321
8322 No other queries may be specified with the same MYSQL handle.
8323 There shouldn't be much processing per row because mysql server shouldn't
8324 have to wait for the client (and will not wait more than 30 sec/packet).
8325 **************************************************************************/
8326
8327 76226 static MYSQL_RES *cli_use_result(MYSQL *mysql) {
8328 MYSQL_RES *result;
8329
1/2
✓ Branch 0 taken 76226 times.
✗ Branch 1 not taken.
76226 DBUG_TRACE;
8330
8331 /*
8332 Some queries (e.g. "CALL") may return an empty resultset.
8333 mysql->field_count is 0 in such cases.
8334 */
8335
2/2
✓ Branch 0 taken 2561 times.
✓ Branch 1 taken 73665 times.
76226 if (!mysql->field_count) return nullptr;
8336
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 73664 times.
73665 if (mysql->status != MYSQL_STATUS_GET_RESULT) {
8337
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
8338 1 return nullptr;
8339 }
8340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73663 times.
73663 if (!(result = (MYSQL_RES *)my_malloc(
8341 key_memory_MYSQL_RES,
8342
1/2
✓ Branch 0 taken 73663 times.
✗ Branch 1 not taken.
73664 sizeof(*result) + sizeof(ulong) * mysql->field_count,
8343 MYF(MY_WME | MY_ZEROFILL))))
8344 return nullptr;
8345 73663 result->lengths = (ulong *)(result + 1);
8346 73663 result->methods = mysql->methods;
8347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73664 times.
73664 if (!(result->row = (MYSQL_ROW)my_malloc(
8348 key_memory_MYSQL_ROW,
8349
1/2
✓ Branch 0 taken 73664 times.
✗ Branch 1 not taken.
73663 sizeof(result->row[0]) * (mysql->field_count + 1),
8350 MYF(MY_WME)))) { /* Ptrs: to one row */
8351 my_free(result);
8352 return nullptr;
8353 }
8354
2/4
✓ Branch 0 taken 73664 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 73664 times.
73664 if (!(result->field_alloc = (MEM_ROOT *)my_malloc(
8355 key_memory_MYSQL, sizeof(MEM_ROOT), MYF(MY_WME | MY_ZEROFILL)))) {
8356 my_free(result->row);
8357 my_free(result);
8358 return nullptr;
8359 }
8360 73664 result->fields = mysql->fields;
8361 73664 *result->field_alloc = std::move(*mysql->field_alloc);
8362 73664 result->field_count = mysql->field_count;
8363 73664 result->metadata = mysql->resultset_metadata;
8364 73664 result->current_field = 0;
8365 73664 result->handle = mysql;
8366 73664 result->current_row = nullptr;
8367 73664 mysql->fields = nullptr; /* fields is now in result */
8368 73664 mysql->status = MYSQL_STATUS_USE_RESULT;
8369 73664 mysql->unbuffered_fetch_owner = &result->unbuffered_fetch_cancelled;
8370 73664 return result; /* Data is read to be fetched */
8371 76226 }
8372
8373 /**************************************************************************
8374 Return next row of the query results
8375 **************************************************************************/
8376
8377 61629379 MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *res) {
8378
1/2
✓ Branch 0 taken 61629388 times.
✗ Branch 1 not taken.
61629379 DBUG_TRACE;
8379
2/2
✓ Branch 0 taken 286739 times.
✓ Branch 1 taken 61342649 times.
61629388 if (!res->data) { /* Unbufferred fetch */
8380
2/2
✓ Branch 0 taken 286733 times.
✓ Branch 1 taken 6 times.
286739 if (!res->eof) {
8381 286733 MYSQL *mysql = res->handle;
8382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 286733 times.
286733 if (mysql->status != MYSQL_STATUS_USE_RESULT) {
8383 set_mysql_error(mysql,
8384 res->unbuffered_fetch_cancelled
8385 ? CR_FETCH_CANCELED
8386 : CR_COMMANDS_OUT_OF_SYNC,
8387 unknown_sqlstate);
8388
3/4
✓ Branch 0 taken 286718 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 243345 times.
✓ Branch 3 taken 43373 times.
286733 } else if (!(read_one_row(mysql, res->field_count, res->row,
8389 res->lengths))) {
8390 243345 res->row_count++;
8391 243345 return res->current_row = res->row;
8392 }
8393
3/8
✓ Branch 0 taken 43389 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43389 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 43389 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
43373 DBUG_PRINT("info", ("end of data"));
8394 43389 res->eof = true;
8395 43389 mysql->status = MYSQL_STATUS_READY;
8396 /*
8397 Reset only if owner points to us: there is a chance that somebody
8398 started new query after mysql_stmt_close():
8399 */
8400
1/2
✓ Branch 0 taken 43389 times.
✗ Branch 1 not taken.
43389 if (mysql->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
8401 43389 mysql->unbuffered_fetch_owner = nullptr;
8402 /* Don't clear handle in mysql_free_result */
8403 43389 res->handle = nullptr;
8404 }
8405 43395 return (MYSQL_ROW) nullptr;
8406 }
8407 {
8408 MYSQL_ROW tmp;
8409
2/2
✓ Branch 0 taken 1255940 times.
✓ Branch 1 taken 60086709 times.
61342649 if (!res->data_cursor) {
8410
3/8
✓ Branch 0 taken 1255940 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1255940 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1255940 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1255940 DBUG_PRINT("info", ("end of data"));
8411 1255940 return res->current_row = (MYSQL_ROW) nullptr;
8412 }
8413 60086709 tmp = res->data_cursor->data;
8414 60086709 res->data_cursor = res->data_cursor->next;
8415 60086709 return res->current_row = tmp;
8416 }
8417 61629389 }
8418 /**
8419 Reads next row of a result set in an asynchronous way.
8420
8421 @param[in] res buffer in which all rows are stored
8422 @param[out] row return pointer to one row from result set
8423
8424 @retval NET_ASYNC_NOT_READY fetch operation not complete, retry again
8425 @retval NET_ASYNC_COMPLETE fetch operation complete
8426 */
8427 222 net_async_status STDCALL mysql_fetch_row_nonblocking(MYSQL_RES *res,
8428 MYSQL_ROW *row) {
8429
1/2
✓ Branch 0 taken 222 times.
✗ Branch 1 not taken.
222 DBUG_TRACE;
8430 222 MYSQL *mysql = res->handle;
8431 222 *row = nullptr;
8432
8433
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 216 times.
222 if (!res->data) { /* Unbufferred fetch */
8434
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!res->eof) {
8435 /*
8436 Can be -1 (error), 0 (success) and 1 (eof).
8437 Init to -1 so if state is not MYSQL_STATUS_USE_RESULT we get
8438 out of sync error.
8439 */
8440 6 int read_row_result = -1;
8441
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (mysql->status == MYSQL_STATUS_USE_RESULT) {
8442
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (read_one_row_nonblocking(mysql, res->field_count, res->row,
8443 res->lengths,
8444
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 &read_row_result) == NET_ASYNC_NOT_READY) {
8445 return NET_ASYNC_NOT_READY;
8446 }
8447
8448 // we arrive here on NET_ASYNC_ERROR or NET_ASYNC_COMPLETE
8449
8450
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 if (read_row_result == 0) { // we've got a row: process it
8451 5 res->row_count++;
8452 5 *row = res->current_row = res->row;
8453 5 goto end;
8454 }
8455 }
8456
8457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (read_row_result == -1) // on row reading error
8458 set_mysql_error(mysql,
8459 res->unbuffered_fetch_cancelled
8460 ? CR_FETCH_CANCELED
8461 : CR_COMMANDS_OUT_OF_SYNC,
8462 unknown_sqlstate);
8463
3/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 DBUG_PRINT("info", ("end of data"));
8464 1 res->eof = true;
8465 1 mysql->status = MYSQL_STATUS_READY;
8466 /*
8467 Reset only if owner points to us: there is a chance that
8468 somebody started new query after mysql_stmt_close():
8469 */
8470
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (mysql->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
8471 1 mysql->unbuffered_fetch_owner = nullptr;
8472 /* Don't clear handle in mysql_free_result */
8473 1 res->handle = nullptr;
8474 }
8475
8476 1 *row = nullptr;
8477 1 goto end;
8478 }
8479 {
8480 MYSQL_ROW tmp;
8481
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 123 times.
216 if (!res->data_cursor) {
8482
3/8
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 93 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 93 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
93 DBUG_PRINT("info", ("end of data"));
8483 93 *row = nullptr;
8484 93 goto end;
8485 }
8486 123 tmp = res->data_cursor->data;
8487 123 res->data_cursor = res->data_cursor->next;
8488 123 *row = res->current_row = tmp;
8489 123 goto end;
8490 }
8491
8492 222 end:
8493 222 return NET_ASYNC_COMPLETE;
8494 222 }
8495
8496 /**************************************************************************
8497 Get column lengths of the current row
8498 If one uses mysql_use_result, res->lengths contains the length information,
8499 else the lengths are calculated from the offset between pointers.
8500 **************************************************************************/
8501
8502 59586318 ulong *STDCALL mysql_fetch_lengths(MYSQL_RES *res) {
8503 MYSQL_ROW column;
8504
8505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59586318 times.
59586318 if (!(column = res->current_row)) return nullptr; /* Something is wrong */
8506
2/2
✓ Branch 0 taken 59373642 times.
✓ Branch 1 taken 212676 times.
59586318 if (res->data)
8507 59373642 (*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
8508 59586319 return res->lengths;
8509 }
8510
8511 /**
8512 Validates, makes into an absolute path and sets @ref
8513 MYSQL_OPT_LOAD_DATA_LOCAL_DIR value
8514
8515 @param mysql connection handle
8516 @param arg the value to set. Can be null
8517
8518 @retval true failed
8519 @retval false success
8520 */
8521 17 static bool set_load_data_local_infile_option(MYSQL *mysql, const char *arg) {
8522 char buff1[FN_REFLEN], buff2[FN_REFLEN];
8523
8524
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
17 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8525
8526 // NULL is a valid argument
8527
3/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 15 times.
17 if (arg == nullptr || !arg[0]) {
8528
2/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2 EXTENSION_SET_STRING(&mysql->options, load_data_dir, nullptr);
8529 2 return false;
8530 }
8531
8532 // make fully qualified name
8533
3/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 14 times.
15 if (my_realpath(buff1, arg, 0)) {
8534 char errbuf[MYSYS_STRERROR_SIZE];
8535
4/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 set_mysql_extended_error(
8536 mysql, CR_LOAD_DATA_LOCAL_INFILE_REALPATH_FAIL, unknown_sqlstate,
8537 ER_CLIENT(CR_LOAD_DATA_LOCAL_INFILE_REALPATH_FAIL), arg, my_errno(),
8538 my_strerror(errbuf, sizeof(errbuf), my_errno()));
8539 1 return true;
8540 }
8541
8542 // with uniform directory separators
8543
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 convert_dirname(buff2, buff1, NullS);
8544
3/8
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
14 EXTENSION_SET_STRING(&mysql->options, load_data_dir, buff2);
8545 14 return false;
8546 }
8547
8548 5419454 int STDCALL mysql_options(MYSQL *mysql, enum mysql_option option,
8549 const void *arg) {
8550
1/2
✓ Branch 0 taken 5419599 times.
✗ Branch 1 not taken.
5419454 DBUG_TRACE;
8551
3/8
✓ Branch 0 taken 5419463 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5419207 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5419207 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
5419599 DBUG_PRINT("enter", ("option: %d", (int)option));
8552
43/44
✓ Branch 0 taken 119104 times.
✓ Branch 1 taken 14171 times.
✓ Branch 2 taken 435 times.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 96945 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 56696 times.
✓ Branch 10 taken 139610 times.
✓ Branch 11 taken 6259 times.
✓ Branch 12 taken 3 times.
✓ Branch 13 taken 3 times.
✓ Branch 14 taken 21481 times.
✓ Branch 15 taken 21 times.
✓ Branch 16 taken 54635 times.
✓ Branch 17 taken 689 times.
✓ Branch 18 taken 134224 times.
✓ Branch 19 taken 134224 times.
✓ Branch 20 taken 134225 times.
✓ Branch 21 taken 134221 times.
✓ Branch 22 taken 134221 times.
✓ Branch 23 taken 134188 times.
✓ Branch 24 taken 134221 times.
✓ Branch 25 taken 134220 times.
✓ Branch 26 taken 134225 times.
✓ Branch 27 taken 131953 times.
✓ Branch 28 taken 147425 times.
✓ Branch 29 taken 46318 times.
✓ Branch 30 taken 91801 times.
✓ Branch 31 taken 131950 times.
✓ Branch 32 taken 2866023 times.
✓ Branch 33 taken 14 times.
✓ Branch 34 taken 2 times.
✓ Branch 35 taken 130691 times.
✓ Branch 36 taken 28919 times.
✓ Branch 37 taken 28483 times.
✓ Branch 38 taken 2 times.
✓ Branch 39 taken 7906 times.
✓ Branch 40 taken 89574 times.
✓ Branch 41 taken 17 times.
✓ Branch 42 taken 42 times.
✗ Branch 43 not taken.
5419214 switch (option) {
8553 119104 case MYSQL_OPT_CONNECT_TIMEOUT:
8554 119104 mysql->options.connect_timeout = *static_cast<const uint *>(arg);
8555 119104 break;
8556 14171 case MYSQL_OPT_READ_TIMEOUT:
8557 14171 mysql->options.read_timeout = *static_cast<const uint *>(arg);
8558 14171 break;
8559 435 case MYSQL_OPT_WRITE_TIMEOUT:
8560 435 mysql->options.write_timeout = *static_cast<const uint *>(arg);
8561 435 break;
8562 64 case MYSQL_OPT_COMPRESS:
8563 64 mysql->options.compress = true; /* Remember for connect */
8564 64 mysql->options.client_flag |= CLIENT_COMPRESS;
8565 64 break;
8566 1 case MYSQL_OPT_NAMED_PIPE: /* This option is deprecated */
8567 1 mysql->options.protocol = MYSQL_PROTOCOL_PIPE; /* Force named pipe */
8568 1 break;
8569 96945 case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/
8570
3/4
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 96869 times.
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
96945 if (!arg || (*static_cast<const uint *>(arg) != 0))
8571 96945 mysql->options.client_flag |= CLIENT_LOCAL_FILES;
8572 else
8573 mysql->options.client_flag &= ~CLIENT_LOCAL_FILES;
8574 96945 break;
8575 4 case MYSQL_INIT_COMMAND:
8576
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 add_init_command(&mysql->options, static_cast<const char *>(arg));
8577 4 break;
8578 2 case MYSQL_READ_DEFAULT_FILE:
8579
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 my_free(mysql->options.my_cnf_file);
8580 2 mysql->options.my_cnf_file =
8581
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 my_strdup(key_memory_mysql_options, static_cast<const char *>(arg),
8582 MYF(MY_WME));
8583 2 break;
8584 2 case MYSQL_READ_DEFAULT_GROUP:
8585
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 my_free(mysql->options.my_cnf_group);
8586 2 mysql->options.my_cnf_group =
8587
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 my_strdup(key_memory_mysql_options, static_cast<const char *>(arg),
8588 MYF(MY_WME));
8589 2 break;
8590 56696 case MYSQL_SET_CHARSET_DIR:
8591
1/2
✓ Branch 0 taken 56696 times.
✗ Branch 1 not taken.
56696 my_free(mysql->options.charset_dir);
8592 56696 mysql->options.charset_dir =
8593
1/2
✓ Branch 0 taken 56696 times.
✗ Branch 1 not taken.
56696 my_strdup(key_memory_mysql_options, static_cast<const char *>(arg),
8594 MYF(MY_WME));
8595 56696 break;
8596 139610 case MYSQL_SET_CHARSET_NAME:
8597
1/2
✓ Branch 0 taken 139610 times.
✗ Branch 1 not taken.
139610 my_free(mysql->options.charset_name);
8598 139611 mysql->options.charset_name =
8599
1/2
✓ Branch 0 taken 139611 times.
✗ Branch 1 not taken.
139610 my_strdup(key_memory_mysql_options, static_cast<const char *>(arg),
8600 MYF(MY_WME));
8601 139611 break;
8602 6259 case MYSQL_OPT_PROTOCOL:
8603 6259 mysql->options.protocol = *static_cast<const uint *>(arg);
8604 6259 break;
8605 3 case MYSQL_SHARED_MEMORY_BASE_NAME:
8606 #if defined(_WIN32)
8607 my_free(mysql->options.shared_memory_base_name);
8608
8609 mysql->options.shared_memory_base_name =
8610 my_strdup(key_memory_mysql_options, static_cast<const char *>(arg),
8611 MYF(MY_WME));
8612 #endif
8613 3 break;
8614 3 case MYSQL_REPORT_DATA_TRUNCATION:
8615 3 mysql->options.report_data_truncation = *static_cast<const bool *>(arg);
8616 3 break;
8617 21481 case MYSQL_OPT_RECONNECT:
8618 21481 mysql->reconnect = *static_cast<const bool *>(arg);
8619 21481 break;
8620 21 case MYSQL_OPT_BIND:
8621
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 my_free(mysql->options.bind_address);
8622 21 mysql->options.bind_address =
8623
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 my_strdup(key_memory_mysql_options, static_cast<const char *>(arg),
8624 MYF(MY_WME));
8625 21 break;
8626 54635 case MYSQL_PLUGIN_DIR:
8627
5/10
✓ Branch 0 taken 54635 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54635 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 54124 times.
✓ Branch 7 taken 511 times.
✓ Branch 8 taken 54124 times.
✗ Branch 9 not taken.
54635 EXTENSION_SET_STRING(&mysql->options, plugin_dir,
8628 static_cast<const char *>(arg));
8629 54635 break;
8630 689 case MYSQL_DEFAULT_AUTH:
8631
5/10
✓ Branch 0 taken 689 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 689 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 178 times.
✓ Branch 7 taken 511 times.
✓ Branch 8 taken 178 times.
✗ Branch 9 not taken.
689 EXTENSION_SET_STRING(&mysql->options, default_auth,
8632 static_cast<const char *>(arg));
8633 689 break;
8634 134224 case MYSQL_OPT_SSL_KEY:
8635
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 134224 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
134224 if (mysql->options.ssl_key) my_free(mysql->options.ssl_key);
8636 134224 mysql->options.ssl_key =
8637
1/2
✓ Branch 0 taken 134224 times.
✗ Branch 1 not taken.
134224 set_ssl_option_unpack_path(static_cast<const char *>(arg));
8638 134224 break;
8639 134224 case MYSQL_OPT_SSL_CERT:
8640
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 134224 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
134224 if (mysql->options.ssl_cert) my_free(mysql->options.ssl_cert);
8641 134224 mysql->options.ssl_cert =
8642
1/2
✓ Branch 0 taken 134224 times.
✗ Branch 1 not taken.
134224 set_ssl_option_unpack_path(static_cast<const char *>(arg));
8643 134224 break;
8644 134225 case MYSQL_OPT_SSL_CA:
8645
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 134225 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
134225 if (mysql->options.ssl_ca) my_free(mysql->options.ssl_ca);
8646 134225 mysql->options.ssl_ca =
8647
1/2
✓ Branch 0 taken 134225 times.
✗ Branch 1 not taken.
134225 set_ssl_option_unpack_path(static_cast<const char *>(arg));
8648 134225 break;
8649 134221 case MYSQL_OPT_SSL_CAPATH:
8650
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 134221 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
134221 if (mysql->options.ssl_capath) my_free(mysql->options.ssl_capath);
8651 134221 mysql->options.ssl_capath =
8652
1/2
✓ Branch 0 taken 134221 times.
✗ Branch 1 not taken.
134221 set_ssl_option_unpack_path(static_cast<const char *>(arg));
8653 134221 break;
8654 134221 case MYSQL_OPT_SSL_CIPHER:
8655
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 134221 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 90 times.
✓ Branch 5 taken 134131 times.
✓ Branch 6 taken 90 times.
✗ Branch 7 not taken.
134221 SET_OPTION(ssl_cipher, static_cast<const char *>(arg));
8656 134221 break;
8657 134188 case MYSQL_OPT_TLS_CIPHERSUITES:
8658
5/10
✓ Branch 0 taken 134188 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 134188 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 16 times.
✓ Branch 7 taken 134172 times.
✓ Branch 8 taken 16 times.
✗ Branch 9 not taken.
134188 EXTENSION_SET_STRING(&mysql->options, tls_ciphersuites,
8659 static_cast<const char *>(arg));
8660 134188 break;
8661 134221 case MYSQL_OPT_SSL_CRL:
8662
2/2
✓ Branch 0 taken 134220 times.
✓ Branch 1 taken 1 times.
134221 if (mysql->options.extension)
8663
1/2
✓ Branch 0 taken 134223 times.
✗ Branch 1 not taken.
134220 my_free(mysql->options.extension->ssl_crl);
8664 else
8665
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
1 ALLOCATE_EXTENSIONS(&mysql->options);
8666 268446 mysql->options.extension->ssl_crl =
8667
1/2
✓ Branch 0 taken 134223 times.
✗ Branch 1 not taken.
134223 set_ssl_option_unpack_path(static_cast<const char *>(arg));
8668 134223 break;
8669 134220 case MYSQL_OPT_SSL_CRLPATH:
8670
1/2
✓ Branch 0 taken 134220 times.
✗ Branch 1 not taken.
134220 if (mysql->options.extension)
8671
1/2
✓ Branch 0 taken 134220 times.
✗ Branch 1 not taken.
134220 my_free(mysql->options.extension->ssl_crlpath);
8672 else
8673 ALLOCATE_EXTENSIONS(&mysql->options);
8674 268440 mysql->options.extension->ssl_crlpath =
8675
1/2
✓ Branch 0 taken 134220 times.
✗ Branch 1 not taken.
134220 set_ssl_option_unpack_path(static_cast<const char *>(arg));
8676 134220 break;
8677 134225 case MYSQL_OPT_TLS_VERSION:
8678
5/10
✓ Branch 0 taken 134225 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 134225 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2311 times.
✓ Branch 7 taken 131914 times.
✓ Branch 8 taken 2311 times.
✗ Branch 9 not taken.
134225 EXTENSION_SET_STRING(&mysql->options, tls_version,
8679 static_cast<const char *>(arg));
8680 268447 if ((mysql->options.extension->ssl_ctx_flags = process_tls_version(
8681
3/4
✓ Branch 0 taken 134222 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 134210 times.
134225 mysql->options.extension->tls_version)) == -1)
8682 12 return 1;
8683 134210 break;
8684 131953 case MYSQL_OPT_SSL_FIPS_MODE: {
8685 131953 char ssl_err_string[OPENSSL_ERROR_LENGTH] = {'\0'};
8686
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 131953 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
131953 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8687 131953 mysql->options.extension->ssl_fips_mode =
8688 131953 *static_cast<const ulong *>(arg);
8689
3/4
✓ Branch 0 taken 131952 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 131950 times.
131953 if (set_fips_mode(mysql->options.extension->ssl_fips_mode,
8690 ssl_err_string)) {
8691
3/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2 DBUG_PRINT("error", ("fips mode set error %s:", ssl_err_string));
8692
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 set_mysql_extended_error(
8693 mysql, CR_SSL_FIPS_MODE_ERR, unknown_sqlstate,
8694 "Set Fips mode ON/STRICT failed, detail: '%s'.", ssl_err_string);
8695 2 return 1;
8696 }
8697 131950 } break;
8698 147425 case MYSQL_OPT_SSL_MODE:
8699
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 147425 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
147425 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8700 147425 mysql->options.extension->ssl_mode = *static_cast<const uint *>(arg);
8701
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 147388 times.
147425 if (mysql->options.extension->ssl_mode == SSL_MODE_VERIFY_IDENTITY)
8702 37 mysql->options.client_flag |= CLIENT_SSL_VERIFY_SERVER_CERT;
8703 else
8704 147388 mysql->options.client_flag &= ~CLIENT_SSL_VERIFY_SERVER_CERT;
8705 147425 break;
8706 46318 case MYSQL_SERVER_PUBLIC_KEY:
8707
4/10
✓ Branch 0 taken 46318 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46318 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 46318 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 46318 times.
✗ Branch 9 not taken.
46318 EXTENSION_SET_STRING(&mysql->options, server_public_key_path,
8708 static_cast<const char *>(arg));
8709 46318 break;
8710
8711 91801 case MYSQL_OPT_GET_SERVER_PUBLIC_KEY:
8712
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 91801 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
91801 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8713 91801 mysql->options.extension->get_server_public_key =
8714 91801 *static_cast<const bool *>(arg);
8715 91801 break;
8716
8717 131950 case MYSQL_OPT_CONNECT_ATTR_RESET:
8718
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 131950 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
131950 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8719
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 131948 times.
131950 if (mysql->options.extension->connection_attributes) {
8720
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 delete mysql->options.extension->connection_attributes;
8721 2 mysql->options.extension->connection_attributes = nullptr;
8722 2 mysql->options.extension->connection_attributes_length = 0;
8723 }
8724 131950 break;
8725 2866023 case MYSQL_OPT_CONNECT_ATTR_DELETE:
8726
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2866023 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2866023 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8727
2/2
✓ Branch 0 taken 2738430 times.
✓ Branch 1 taken 127593 times.
2866023 if (mysql->options.extension->connection_attributes) {
8728
2/4
✓ Branch 0 taken 2738430 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2738431 times.
✗ Branch 3 not taken.
2738430 string key = arg ? pointer_cast<const char *>(arg) : "";
8729
8730
1/2
✓ Branch 0 taken 2738430 times.
✗ Branch 1 not taken.
2738430 if (!key.empty()) {
8731 auto it =
8732
1/2
✓ Branch 0 taken 2738431 times.
✗ Branch 1 not taken.
2738430 mysql->options.extension->connection_attributes->hash.find(key);
8733 2738431 if (it !=
8734
2/2
✓ Branch 0 taken 1585101 times.
✓ Branch 1 taken 1153330 times.
5476862 mysql->options.extension->connection_attributes->hash.end()) {
8735 1585101 const string &attr_key = it->first;
8736 1585101 const string &attr_value = it->second;
8737 1585101 mysql->options.extension->connection_attributes_length -=
8738
1/2
✓ Branch 0 taken 1585101 times.
✗ Branch 1 not taken.
1585101 get_length_store_length(attr_key.size()) + attr_key.size() +
8739
1/2
✓ Branch 0 taken 1585101 times.
✗ Branch 1 not taken.
1585101 get_length_store_length(attr_value.size()) + attr_value.size();
8740
8741
1/2
✓ Branch 0 taken 1585101 times.
✗ Branch 1 not taken.
1585101 mysql->options.extension->connection_attributes->hash.erase(it);
8742 }
8743 }
8744 2738431 }
8745 2866023 break;
8746 14 case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
8747
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
14 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8748 14 mysql->options.extension->enable_cleartext_plugin =
8749 14 *static_cast<const bool *>(arg);
8750 14 break;
8751 2 case MYSQL_OPT_RETRY_COUNT:
8752
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8753 2 mysql->options.extension->retry_count = *static_cast<const uint *>(arg);
8754 2 break;
8755 130691 case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
8756
2/2
✓ Branch 0 taken 96373 times.
✓ Branch 1 taken 34318 times.
130691 if (*static_cast<const bool *>(arg))
8757 96373 mysql->options.client_flag |= CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
8758 else
8759 34318 mysql->options.client_flag &= ~CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
8760 130691 break;
8761
8762 28919 case MYSQL_OPT_MAX_ALLOWED_PACKET:
8763
2/2
✓ Branch 0 taken 438 times.
✓ Branch 1 taken 28481 times.
28919 if (mysql)
8764 438 mysql->options.max_allowed_packet = *static_cast<const ulong *>(arg);
8765 else
8766 28481 g_max_allowed_packet = *static_cast<const ulong *>(arg);
8767 28919 break;
8768
8769 28483 case MYSQL_OPT_NET_BUFFER_LENGTH:
8770 28483 g_net_buffer_length = *static_cast<const ulong *>(arg);
8771 28483 break;
8772
8773 2 case MYSQL_OPT_OPTIONAL_RESULTSET_METADATA:
8774
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (*static_cast<const bool *>(arg))
8775 2 mysql->options.client_flag |= CLIENT_OPTIONAL_RESULTSET_METADATA;
8776 else
8777 mysql->options.client_flag &= ~CLIENT_OPTIONAL_RESULTSET_METADATA;
8778 2 break;
8779
8780 7906 case MYSQL_OPT_COMPRESSION_ALGORITHMS: {
8781
1/2
✓ Branch 0 taken 7906 times.
✗ Branch 1 not taken.
7906 std::string compress_option(static_cast<const char *>(arg));
8782 7906 std::vector<std::string> list;
8783
2/4
✓ Branch 0 taken 7906 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7906 times.
✗ Branch 3 not taken.
7906 parse_compression_algorithms_list(compress_option, list);
8784
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7906 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
7906 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8785 7906 mysql->options.extension->connection_compressed = true;
8786 7906 mysql->options.client_flag &=
8787 ~(CLIENT_COMPRESS | CLIENT_ZSTD_COMPRESSION_ALGORITHM);
8788 7906 mysql->options.compress = false;
8789 7906 auto it = list.begin();
8790 7906 unsigned int cnt = 0;
8791
5/6
✓ Branch 0 taken 8034 times.
✓ Branch 1 taken 7906 times.
✓ Branch 2 taken 8034 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8034 times.
✓ Branch 5 taken 7906 times.
15940 while (it != list.end() && cnt < COMPRESSION_ALGORITHM_COUNT_MAX) {
8792
1/2
✓ Branch 0 taken 8034 times.
✗ Branch 1 not taken.
8034 std::string value = *it;
8793
6/9
✓ Branch 0 taken 8034 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8034 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 146 times.
✓ Branch 5 taken 144 times.
✓ Branch 6 taken 7741 times.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
8034 switch (get_compression_algorithm(value)) {
8794 146 case enum_compression_algorithm::MYSQL_ZLIB:
8795 146 mysql->options.client_flag |= CLIENT_COMPRESS;
8796 146 mysql->options.compress = true;
8797 146 break;
8798 144 case enum_compression_algorithm::MYSQL_ZSTD:
8799 144 mysql->options.client_flag |= CLIENT_ZSTD_COMPRESSION_ALGORITHM;
8800 144 mysql->options.compress = true;
8801 144 break;
8802 7741 case enum_compression_algorithm::MYSQL_UNCOMPRESSED:
8803 7741 mysql->options.extension->connection_compressed = false;
8804 7741 break;
8805 3 case enum_compression_algorithm::MYSQL_INVALID:
8806 3 break; // report error
8807 }
8808 8034 it++;
8809 8034 cnt++;
8810 8034 }
8811
2/2
✓ Branch 0 taken 7905 times.
✓ Branch 1 taken 1 times.
7906 if (cnt)
8812
4/10
✓ Branch 0 taken 7905 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7905 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 7905 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7905 times.
✗ Branch 9 not taken.
7905 EXTENSION_SET_STRING(&mysql->options, compression_algorithm,
8813 static_cast<const char *>(arg));
8814 7906 mysql->options.extension->total_configured_compression_algorithms = cnt;
8815 7906 } break;
8816 89574 case MYSQL_OPT_ZSTD_COMPRESSION_LEVEL:
8817
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 89574 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
89574 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8818 89574 mysql->options.extension->zstd_compression_level =
8819 89574 *static_cast<const unsigned int *>(arg);
8820 89574 break;
8821
8822 17 case MYSQL_OPT_LOAD_DATA_LOCAL_DIR:
8823
3/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 16 times.
17 if (set_load_data_local_infile_option(mysql,
8824 static_cast<const char *>(arg)))
8825 1 return 1;
8826 16 break;
8827 42 case MYSQL_OPT_SSL_SESSION_DATA:
8828
4/10
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 42 times.
✗ Branch 9 not taken.
42 EXTENSION_SET_STRING(&mysql->options, ssl_session_data,
8829 static_cast<const char *>(arg));
8830 42 break;
8831 default:
8832 return 1;
8833 }
8834 5419134 return 0;
8835 5419149 }
8836
8837 /**
8838 Return the current values for the options settable through mysql_options()
8839
8840 Returns the current values for all of the connection options.
8841 Callers should not manipulate the returned data !
8842 Data are valid at the time of returning them until the next C API CALL
8843 arg should always be a pointer to a variable of the appropriate type.
8844 type of variable, based on the parameter:
8845
8846 uint
8847 MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_READ_TIMEOUT, MYSQL_OPT_WRITE_TIMEOUT,
8848 MYSQL_OPT_PROTOCOL, MYSQL_OPT_SSL_MODE, MYSQL_OPT_RETRY_COUNT
8849
8850 bool
8851 MYSQL_OPT_COMPRESS, MYSQL_OPT_LOCAL_INFILE,
8852 MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
8853 MYSQL_ENABLE_CLEARTEXT_PLUGIN, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS,
8854 MYSQL_OPT_OPTIONAL_RESULTSET_METADATA
8855
8856 const char *
8857 MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP,
8858 MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME,
8859 MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_SET_CLIENT_IP, MYSQL_OPT_BIND,
8860 MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH, MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT,
8861 MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, MYSQL_OPT_SSL_CIPHER,
8862 MYSQL_OPT_TLS_CIPHERSUITES, MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH,
8863 MYSQL_OPT_TLS_VERSION, MYSQL_SERVER_PUBLIC_KEY, MYSQL_OPT_SSL_FIPS_MODE
8864
8865 <none, error returned>
8866 MYSQL_OPT_NAMED_PIPE, MYSQL_OPT_CONNECT_ATTR_RESET,
8867 MYSQL_OPT_CONNECT_ATTR_DELETE, MYSQL_INIT_COMMAND
8868
8869 @param mysql The MYSQL connection to operate on
8870 @param option The option to return the value for
8871 @param [out] arg Must be non-null. Receives the current value.
8872 @return status
8873 @retval 0 SUCCESS
8874 */
8875
8876 434392 int STDCALL mysql_get_option(MYSQL *mysql, enum mysql_option option,
8877 const void *arg) {
8878
1/2
✓ Branch 0 taken 434436 times.
✗ Branch 1 not taken.
434392 DBUG_TRACE;
8879
3/8
✓ Branch 0 taken 434419 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 434381 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 434381 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
434436 DBUG_PRINT("enter", ("option: %d", (int)option));
8880
8881
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 434374 times.
434374 if (!arg) return 1;
8882
8883
36/38
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 27779 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 3 times.
✓ Branch 13 taken 3 times.
✓ Branch 14 taken 27784 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✓ Branch 17 taken 3 times.
✓ Branch 18 taken 3 times.
✓ Branch 19 taken 3 times.
✓ Branch 20 taken 3 times.
✓ Branch 21 taken 3 times.
✓ Branch 22 taken 3 times.
✓ Branch 23 taken 3 times.
✓ Branch 24 taken 3 times.
✓ Branch 25 taken 2 times.
✓ Branch 26 taken 3 times.
✓ Branch 27 taken 3 times.
✓ Branch 28 taken 3 times.
✓ Branch 29 taken 2 times.
✓ Branch 30 taken 3 times.
✓ Branch 31 taken 3 times.
✓ Branch 32 taken 191722 times.
✓ Branch 33 taken 186950 times.
✓ Branch 34 taken 2 times.
✓ Branch 35 taken 5 times.
✓ Branch 36 taken 2 times.
✓ Branch 37 taken 44 times.
434374 switch (option) {
8884 5 case MYSQL_OPT_CONNECT_TIMEOUT:
8885 5 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8886 5 mysql->options.connect_timeout;
8887 5 break;
8888 5 case MYSQL_OPT_READ_TIMEOUT:
8889 5 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8890 5 mysql->options.read_timeout;
8891 5 break;
8892 5 case MYSQL_OPT_WRITE_TIMEOUT:
8893 5 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8894 5 mysql->options.write_timeout;
8895 5 break;
8896 3 case MYSQL_OPT_COMPRESS:
8897 3 *(const_cast<bool *>(static_cast<const bool *>(arg))) =
8898 3 mysql->options.compress;
8899 3 break;
8900 3 case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/
8901 3 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8902 3 (mysql->options.client_flag & CLIENT_LOCAL_FILES) != 0;
8903 3 break;
8904 3 case MYSQL_READ_DEFAULT_FILE:
8905 3 *(static_cast<char **>(const_cast<void *>(arg))) =
8906 3 mysql->options.my_cnf_file;
8907 3 break;
8908 3 case MYSQL_READ_DEFAULT_GROUP:
8909 3 *(static_cast<char **>(const_cast<void *>(arg))) =
8910 3 mysql->options.my_cnf_group;
8911 3 break;
8912 3 case MYSQL_SET_CHARSET_DIR:
8913 3 *(static_cast<char **>(const_cast<void *>(arg))) =
8914 3 mysql->options.charset_dir;
8915 3 break;
8916 3 case MYSQL_SET_CHARSET_NAME:
8917 3 *(static_cast<char **>(const_cast<void *>(arg))) =
8918 3 mysql->options.charset_name;
8919 3 break;
8920 27779 case MYSQL_OPT_PROTOCOL:
8921 27779 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8922 27779 mysql->options.protocol;
8923 27779 break;
8924 case MYSQL_SHARED_MEMORY_BASE_NAME:
8925 #if defined(_WIN32)
8926 *(static_cast<char **>(const_cast<void *>(arg))) =
8927 mysql->options.shared_memory_base_name;
8928 #else
8929 *(static_cast<char **>(const_cast<void *>(arg))) = const_cast<char *>("");
8930 #endif
8931 break;
8932 1 case MYSQL_REPORT_DATA_TRUNCATION:
8933 1 *(const_cast<bool *>(static_cast<const bool *>(arg))) =
8934 1 mysql->options.report_data_truncation;
8935 1 break;
8936 3 case MYSQL_OPT_RECONNECT:
8937 3 *(const_cast<bool *>(static_cast<const bool *>(arg))) = mysql->reconnect;
8938 3 break;
8939 3 case MYSQL_OPT_BIND:
8940 3 *(static_cast<char **>(const_cast<void *>(arg))) =
8941 3 mysql->options.bind_address;
8942 3 break;
8943 27784 case MYSQL_OPT_SSL_MODE:
8944 27784 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8945
1/2
✓ Branch 0 taken 27784 times.
✗ Branch 1 not taken.
27784 mysql->options.extension ? mysql->options.extension->ssl_mode : 0;
8946 27784 break;
8947 case MYSQL_OPT_SSL_FIPS_MODE:
8948 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8949 mysql->options.extension ? mysql->options.extension->ssl_fips_mode
8950 : 0;
8951 break;
8952 3 case MYSQL_PLUGIN_DIR:
8953 3 *(static_cast<char **>(const_cast<void *>(arg))) =
8954
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 mysql->options.extension ? mysql->options.extension->plugin_dir
8955 : nullptr;
8956 3 break;
8957 3 case MYSQL_DEFAULT_AUTH:
8958 3 *(static_cast<char **>(const_cast<void *>(arg))) =
8959
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 mysql->options.extension ? mysql->options.extension->default_auth
8960 : nullptr;
8961 3 break;
8962 3 case MYSQL_OPT_SSL_KEY:
8963 3 *(static_cast<char **>(const_cast<void *>(arg))) = mysql->options.ssl_key;
8964 3 break;
8965 3 case MYSQL_OPT_SSL_CERT:
8966 3 *(static_cast<char **>(const_cast<void *>(arg))) =
8967 3 mysql->options.ssl_cert;
8968 3 break;
8969 3 case MYSQL_OPT_SSL_CA:
8970 3 *(static_cast<char **>(const_cast<void *>(arg))) = mysql->options.ssl_ca;
8971 3 break;
8972 3 case MYSQL_OPT_SSL_CAPATH:
8973 3 *(static_cast<char **>(const_cast<void *>(arg))) =
8974 3 mysql->options.ssl_capath;
8975 3 break;
8976 3 case MYSQL_OPT_SSL_CIPHER:
8977 3 *(static_cast<char **>(const_cast<void *>(arg))) =
8978 3 mysql->options.ssl_cipher;
8979 3 break;
8980 3 case MYSQL_OPT_TLS_CIPHERSUITES:
8981 3 *(static_cast<char **>(const_cast<void *>(arg))) =
8982
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 mysql->options.extension ? mysql->options.extension->tls_ciphersuites
8983 : nullptr;
8984 3 break;
8985 3 case MYSQL_OPT_RETRY_COUNT:
8986 3 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8987
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 mysql->options.extension ? mysql->options.extension->retry_count : 1;
8988 3 break;
8989 2 case MYSQL_OPT_TLS_VERSION:
8990 2 *(static_cast<char **>(const_cast<void *>(arg))) =
8991
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mysql->options.extension ? mysql->options.extension->tls_version
8992 : nullptr;
8993 2 break;
8994 3 case MYSQL_OPT_SSL_CRL:
8995 3 *(static_cast<char **>(const_cast<void *>(arg))) =
8996
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 mysql->options.extension ? mysql->options.extension->ssl_crl
8997 : nullptr;
8998 3 break;
8999 3 case MYSQL_OPT_SSL_CRLPATH:
9000 3 *(static_cast<char **>(const_cast<void *>(arg))) =
9001
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 mysql->options.extension ? mysql->options.extension->ssl_crlpath
9002 : nullptr;
9003 3 break;
9004 3 case MYSQL_SERVER_PUBLIC_KEY:
9005 3 *(static_cast<char **>(const_cast<void *>(arg))) =
9006 3 mysql->options.extension
9007
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 ? mysql->options.extension->server_public_key_path
9008 : nullptr;
9009 3 break;
9010 2 case MYSQL_OPT_GET_SERVER_PUBLIC_KEY:
9011 2 *(const_cast<bool *>(static_cast<const bool *>(arg))) =
9012
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 mysql->options.extension &&
9013
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 mysql->options.extension->get_server_public_key;
9014 2 break;
9015 3 case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
9016 3 *(const_cast<bool *>(static_cast<const bool *>(arg))) =
9017
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 mysql->options.extension &&
9018
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 mysql->options.extension->enable_cleartext_plugin;
9019 3 break;
9020 3 case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
9021 3 *(const_cast<bool *>(static_cast<const bool *>(arg))) =
9022 3 (mysql->options.client_flag & CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS) !=
9023 0;
9024 3 break;
9025
9026 191722 case MYSQL_OPT_MAX_ALLOWED_PACKET:
9027
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 191718 times.
191722 if (mysql)
9028 4 *(const_cast<ulong *>(static_cast<const ulong *>(arg))) =
9029 4 mysql->options.max_allowed_packet;
9030 else
9031 191718 *(const_cast<ulong *>(static_cast<const ulong *>(arg))) =
9032 g_max_allowed_packet;
9033 191722 break;
9034
9035 186950 case MYSQL_OPT_NET_BUFFER_LENGTH:
9036 186950 *(const_cast<ulong *>(static_cast<const ulong *>(arg))) =
9037 g_net_buffer_length;
9038 186950 break;
9039
9040 2 case MYSQL_OPT_OPTIONAL_RESULTSET_METADATA:
9041 2 *(const_cast<bool *>(static_cast<const bool *>(arg))) =
9042 2 (mysql->options.client_flag & CLIENT_OPTIONAL_RESULTSET_METADATA) !=
9043 0;
9044 2 break;
9045 5 case MYSQL_OPT_LOAD_DATA_LOCAL_DIR:
9046 5 *(static_cast<char **>(const_cast<void *>(arg))) =
9047
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 mysql->options.extension ? mysql->options.extension->load_data_dir
9048 : nullptr;
9049 5 break;
9050 2 case MYSQL_OPT_SSL_SESSION_DATA:
9051 2 *(static_cast<char **>(const_cast<void *>(arg))) =
9052 2 mysql->options.extension
9053
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 ? static_cast<char *>(mysql->options.extension->ssl_session_data)
9054 : nullptr;
9055 2 break;
9056
9057 44 case MYSQL_OPT_NAMED_PIPE: /* This option is deprecated */
9058 case MYSQL_INIT_COMMAND: /* Cumulative */
9059 case MYSQL_OPT_CONNECT_ATTR_RESET: /* Cumulative */
9060 case MYSQL_OPT_CONNECT_ATTR_DELETE: /* Cumulative */
9061 default:
9062 44 return 1;
9063 }
9064 434330 return 0;
9065 434374 }
9066
9067 2621630 int STDCALL mysql_options4(MYSQL *mysql, enum mysql_option option,
9068 const void *arg1, const void *arg2) {
9069
1/2
✓ Branch 0 taken 2621794 times.
✗ Branch 1 not taken.
2621630 DBUG_TRACE;
9070
3/8
✓ Branch 0 taken 2621667 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2621566 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2621566 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2621794 DBUG_PRINT("enter", ("option: %d", (int)option));
9071
9072
2/3
✓ Branch 0 taken 2571951 times.
✓ Branch 1 taken 49624 times.
✗ Branch 2 not taken.
2621575 switch (option) {
9073 2571951 case MYSQL_OPT_CONNECT_ATTR_ADD: {
9074 2571951 const char *key = static_cast<const char *>(arg1);
9075 2571951 const char *value = static_cast<const char *>(arg2);
9076
2/2
✓ Branch 0 taken 2571908 times.
✓ Branch 1 taken 43 times.
2571951 size_t key_len = arg1 ? strlen(key) : 0;
9077
2/2
✓ Branch 0 taken 2571945 times.
✓ Branch 1 taken 6 times.
2571951 size_t value_len = arg2 ? strlen(value) : 0;
9078 2571951 size_t attr_storage_length = key_len + value_len;
9079
9080 /* we can't have a zero length key */
9081
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2571951 times.
2571951 if (!key_len) {
9082 set_mysql_error(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
9083 1057 return 1;
9084 }
9085
9086 /* calculate the total storage length of the attribute */
9087
1/2
✓ Branch 0 taken 2571963 times.
✗ Branch 1 not taken.
2571951 attr_storage_length += get_length_store_length(key_len);
9088
1/2
✓ Branch 0 taken 2571904 times.
✗ Branch 1 not taken.
2571963 attr_storage_length += get_length_store_length(value_len);
9089
9090
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2571904 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2571904 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
9091
9092 /*
9093 Throw and error if the maximum combined length of the attribute value
9094 will be greater than the maximum that we can safely transmit.
9095 */
9096 2571904 if (attr_storage_length +
9097
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2571904 times.
2571904 mysql->options.extension->connection_attributes_length >
9098 MAX_CONNECTION_ATTR_STORAGE_LENGTH) {
9099 set_mysql_error(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
9100 return 1;
9101 }
9102
9103
2/2
✓ Branch 0 taken 160698 times.
✓ Branch 1 taken 2411206 times.
2571904 if (!mysql->options.extension->connection_attributes) {
9104 160682 mysql->options.extension->connection_attributes =
9105
1/2
✓ Branch 0 taken 160697 times.
✗ Branch 1 not taken.
321380 new (std::nothrow) My_hash();
9106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160682 times.
160682 if (!mysql->options.extension->connection_attributes) {
9107 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
9108 return 1;
9109 }
9110 }
9111 5143938 if (!mysql->options.extension->connection_attributes->hash
9112
1/2
✓ Branch 0 taken 2572050 times.
✗ Branch 1 not taken.
2571888 .emplace(key, value)
9113
2/2
✓ Branch 0 taken 1057 times.
✓ Branch 1 taken 2570993 times.
2572050 .second) {
9114 /* can't insert the value */
9115
1/2
✓ Branch 0 taken 1057 times.
✗ Branch 1 not taken.
1057 set_mysql_error(mysql, CR_DUPLICATE_CONNECTION_ATTR, unknown_sqlstate);
9116 1057 return 1;
9117 }
9118
9119 2570993 mysql->options.extension->connection_attributes_length +=
9120 attr_storage_length;
9121
9122 2570993 break;
9123 }
9124 49624 case MYSQL_OPT_USER_PASSWORD: {
9125 49624 unsigned int factor = *static_cast<const uint *>(arg1) - 1;
9126
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 49624 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
49624 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
9127 switch (factor) {
9128 49609 case 0:
9129
1/2
✓ Branch 0 taken 49611 times.
✗ Branch 1 not taken.
49609 my_free(mysql->options.extension->client_auth_info[0].password);
9130 99251 mysql->options.extension->client_auth_info[0].password =
9131
1/2
✓ Branch 0 taken 49640 times.
✗ Branch 1 not taken.
49611 my_strdup(key_memory_mysql_options,
9132 static_cast<const char *>(arg2), MYF(MY_FAE));
9133 49640 break;
9134 case 1:
9135 my_free(mysql->options.extension->client_auth_info[1].password);
9136 mysql->options.extension->client_auth_info[1].password =
9137 my_strdup(key_memory_mysql_options,
9138 static_cast<const char *>(arg2), MYF(MY_FAE));
9139 break;
9140 case 2:
9141 my_free(mysql->options.extension->client_auth_info[2].password);
9142 mysql->options.extension->client_auth_info[2].password =
9143 my_strdup(key_memory_mysql_options,
9144 static_cast<const char *>(arg2), MYF(MY_FAE));
9145 break;
9146 15 default:
9147
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
15 set_mysql_error(mysql, CR_INVALID_FACTOR_NO, unknown_sqlstate);
9148 return 1;
9149 }
9150 49640 break;
9151 }
9152 default:
9153 return 1;
9154 }
9155 2620633 return 0;
9156 2621690 }
9157
9158 /****************************************************************************
9159 Functions to get information from the MySQL structure
9160 These are functions to make shared libraries more usable.
9161 ****************************************************************************/
9162
9163 /* MYSQL_RES */
9164 64065 my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res) { return res->row_count; }
9165
9166 19092278 unsigned int STDCALL mysql_num_fields(MYSQL_RES *res) {
9167 19092278 return res->field_count;
9168 }
9169
9170 5057312 uint STDCALL mysql_errno(MYSQL *mysql) {
9171
1/2
✓ Branch 0 taken 5057312 times.
✗ Branch 1 not taken.
5057312 return mysql ? mysql->net.last_errno : mysql_server_last_errno;
9172 }
9173
9174 835196 const char *STDCALL mysql_error(MYSQL *mysql) {
9175
1/2
✓ Branch 0 taken 835196 times.
✗ Branch 1 not taken.
835196 return mysql ? mysql->net.last_error : mysql_server_last_error;
9176 }
9177
9178 /**
9179 Read data and its length from a LIST node.
9180
9181 Assumes LIST which stores data blobs in LEX_STRING structures,
9182 where LEX_STRING::str is pointer to the data and LEX_STRING::length
9183 is the length of this data.
9184
9185 If node is NULL then data and length are set to NULL and 0, respectively,
9186 and function returns 0, otherwise, if data has been read from the node,
9187 function returns 1.
9188 */
9189
9190 4006 static int get_data_and_length(LIST *node, const char **data, size_t *length) {
9191
3/4
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 3528 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 478 times.
4006 assert(!node || node->data);
9192
3/4
✓ Branch 0 taken 4006 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 478 times.
✓ Branch 3 taken 3528 times.
4006 if (data) *data = node ? ((LEX_STRING *)(node->data))->str : nullptr;
9193
3/4
✓ Branch 0 taken 4006 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 478 times.
✓ Branch 3 taken 3528 times.
4006 if (length) *length = node ? ((LEX_STRING *)(node->data))->length : 0;
9194
9195 4006 return node ? 0 : 1;
9196 }
9197
9198 /**
9199 Get the first state change information received from the server.
9200
9201 @param [in] mysql mysql handle
9202 @param [in] type state change type
9203 @param [out] data buffer to store the data
9204 @param [out] length length of the data
9205
9206 @return
9207 0 - Valid data stored
9208 1 - No data
9209 */
9210
9211 3528 int STDCALL mysql_session_track_get_first(MYSQL *mysql,
9212 enum enum_session_state_type type,
9213 const char **data, size_t *length) {
9214
2/4
✓ Branch 0 taken 3528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3528 times.
✗ Branch 3 not taken.
3528 STATE_INFO *info = STATE_DATA(mysql);
9215
9216
3/6
✓ Branch 0 taken 3528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3528 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3528 times.
✗ Branch 5 not taken.
3528 if (!info || !IS_SESSION_STATE_TYPE(type) ||
9217
2/2
✓ Branch 0 taken 3141 times.
✓ Branch 1 taken 387 times.
3528 !(info->info_list[type].head_node))
9218 3141 return get_data_and_length(nullptr, data, length);
9219
9220 387 info->info_list[type].current_node = info->info_list[type].head_node;
9221
9222 387 return mysql_session_track_get_next(mysql, type, data, length);
9223 }
9224
9225 /**
9226 Get the subsequent state change information received from the server.
9227
9228 @param [in] mysql mysql handle
9229 @param [in] type state change type
9230 @param [out] data buffer to store the data
9231 @param [out] length length of the data
9232
9233 @return
9234 0 - Valid data stored
9235 1 - No data
9236 */
9237
9238 865 int STDCALL mysql_session_track_get_next(MYSQL *mysql,
9239 enum enum_session_state_type type,
9240 const char **data, size_t *length) {
9241
2/4
✓ Branch 0 taken 865 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 865 times.
✗ Branch 3 not taken.
865 STATE_INFO *info = STATE_DATA(mysql);
9242 int ret;
9243
9244
3/6
✓ Branch 0 taken 865 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 865 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 865 times.
✗ Branch 5 not taken.
865 if (!info || !IS_SESSION_STATE_TYPE(type) ||
9245
2/2
✓ Branch 0 taken 387 times.
✓ Branch 1 taken 478 times.
865 !(info->info_list[type].current_node))
9246 387 return get_data_and_length(nullptr, data, length);
9247
9248 478 ret = get_data_and_length(info->info_list[type].current_node, data, length);
9249
9250 478 info->info_list[type].current_node =
9251 478 list_rest(info->info_list[type].current_node);
9252
9253 478 return ret;
9254 }
9255
9256 /*
9257 Get version number for server in a form easy to test on
9258
9259 SYNOPSIS
9260 mysql_get_server_version()
9261 mysql Connection
9262
9263 EXAMPLE
9264 4.1.0-alfa -> 40100
9265
9266 NOTES
9267 We will ensure that a newer server always has a bigger number.
9268
9269 RETURN
9270 Signed number > 323000
9271 Zero if there is no connection
9272 */
9273
9274 1147357 ulong STDCALL mysql_get_server_version(MYSQL *mysql) {
9275 1147357 ulong major = 0, minor = 0, version = 0;
9276
9277
1/2
✓ Branch 0 taken 1147357 times.
✗ Branch 1 not taken.
1147357 if (mysql->server_version) {
9278 1147357 char *pos = mysql->server_version, *end_pos;
9279 1147357 major = strtoul(pos, &end_pos, 10);
9280 1147357 pos = end_pos + 1;
9281 1147357 minor = strtoul(pos, &end_pos, 10);
9282 1147357 pos = end_pos + 1;
9283 1147357 version = strtoul(pos, &end_pos, 10);
9284 } else {
9285 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
9286 }
9287
9288 1147357 return major * 10000 + minor * 100 + version;
9289 }
9290
9291 /*
9292 mysql_set_character_set function sends SET NAMES cs_name to
9293 the server (which changes character_set_client, character_set_result
9294 and character_set_connection) and updates mysql->charset so other
9295 functions like mysql_real_escape will work correctly.
9296 */
9297 39110 int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name) {
9298 CHARSET_INFO *cs;
9299 39110 const char *save_csdir = charsets_dir;
9300
9301
2/2
✓ Branch 0 taken 9568 times.
✓ Branch 1 taken 29542 times.
39110 if (mysql->options.charset_dir) {
9302 #ifdef MYSQL_SERVER
9303 // Do not change charsets_dir, it is not thread safe.
9304 assert(false);
9305 #else
9306 9568 charsets_dir = mysql->options.charset_dir;
9307 #endif
9308 }
9309
2/2
✓ Branch 0 taken 28061 times.
✓ Branch 1 taken 11049 times.
39110 if (!mysql->net.vio) {
9310 /* Initialize with automatic OS character set detection. */
9311 28061 mysql_options(mysql, MYSQL_SET_CHARSET_NAME, cs_name);
9312 28061 mysql_init_character_set(mysql);
9313 /*
9314 In case of automatic OS character set detection
9315 mysql_init_character_set changes mysql->options.charset_name
9316 from "auto" to the real character set name.
9317 Reset cs_name to the detected character set name, accordingly.
9318 */
9319 28061 cs_name = mysql->options.charset_name;
9320 }
9321
9322
2/4
✓ Branch 0 taken 39110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39110 times.
✗ Branch 3 not taken.
78220 if (strlen(cs_name) < MY_CS_NAME_SIZE &&
9323
1/2
✓ Branch 0 taken 39110 times.
✗ Branch 1 not taken.
39110 (cs = get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0)))) {
9324 char buff[MY_CS_NAME_SIZE + 10];
9325 39110 charsets_dir = save_csdir;
9326
2/2
✓ Branch 0 taken 28061 times.
✓ Branch 1 taken 11049 times.
39110 if (!mysql->net.vio) {
9327 /* If there is no connection yet we don't send "SET NAMES" query */
9328 28061 mysql->charset = cs;
9329 28061 return 0;
9330 }
9331 /* Skip execution of "SET NAMES" for pre-4.1 servers */
9332
2/4
✓ Branch 0 taken 11049 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11049 times.
11049 if (mysql_get_server_version(mysql) < 40100) return 0;
9333 11049 sprintf(buff, "SET NAMES %s", cs_name);
9334
2/4
✓ Branch 0 taken 11049 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11049 times.
✗ Branch 3 not taken.
11049 if (!mysql_real_query(mysql, buff, (ulong)strlen(buff))) {
9335 11049 mysql->charset = cs;
9336 }
9337 } else {
9338 char cs_dir_name[FN_REFLEN];
9339 get_charsets_dir(cs_dir_name);
9340 set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
9341 ER_CLIENT(CR_CANT_READ_CHARSET), cs_name,
9342 cs_dir_name);
9343 }
9344 11049 charsets_dir = save_csdir;
9345 11049 return mysql->net.last_errno;
9346 }
9347
9348 /**
9349 Client authentication plugin that does native MySQL authentication
9350 using a 20-byte (4.1+) scramble
9351
9352 @param vio the channel to operate on
9353 @param mysql the MYSQL structure to operate on
9354
9355 @retval -1 ::CR_OK : Success
9356 @retval 1 ::CR_ERROR : error reading
9357 @retval 2012 ::CR_SERVER_HANDSHAKE_ERR : malformed handshake data
9358 */
9359 7541 static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) {
9360 int pkt_len;
9361 uchar *pkt;
9362
9363
1/2
✓ Branch 0 taken 7541 times.
✗ Branch 1 not taken.
7541 DBUG_TRACE;
9364
9365 /* read the scramble */
9366
3/4
✓ Branch 0 taken 7541 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 7508 times.
7541 if ((pkt_len = vio->read_packet(vio, &pkt)) < 0) return CR_ERROR;
9367
9368
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7508 times.
7508 if (pkt_len != SCRAMBLE_LENGTH + 1) return CR_SERVER_HANDSHAKE_ERR;
9369
9370 /* save it in MYSQL */
9371 7508 memcpy(mysql->scramble, pkt, SCRAMBLE_LENGTH);
9372 7508 mysql->scramble[SCRAMBLE_LENGTH] = 0;
9373
9374
2/2
✓ Branch 0 taken 5631 times.
✓ Branch 1 taken 1877 times.
7508 if (mysql->passwd[0]) {
9375 char scrambled[SCRAMBLE_LENGTH + 1];
9376
3/8
✓ Branch 0 taken 5631 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5631 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5631 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
5631 DBUG_PRINT("info", ("sending scramble"));
9377
1/2
✓ Branch 0 taken 5631 times.
✗ Branch 1 not taken.
5631 scramble(scrambled, (char *)pkt, mysql->passwd);
9378
2/4
✓ Branch 0 taken 5631 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5631 times.
5631 if (vio->write_packet(vio, (uchar *)scrambled, SCRAMBLE_LENGTH))
9379 return CR_ERROR;
9380 } else {
9381
3/8
✓ Branch 0 taken 1877 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1877 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1877 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1877 DBUG_PRINT("info", ("no password"));
9382
2/4
✓ Branch 0 taken 1877 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1877 times.
1877 if (vio->write_packet(vio, nullptr, 0)) /* no password */
9383 return CR_ERROR;
9384 }
9385
9386 7508 return CR_OK;
9387 7541 }
9388
9389 /**
9390 Client authentication plugin that does native MySQL authentication
9391 in a nonblocking way.
9392
9393 @param[in] vio the channel to operate on
9394 @param[in] mysql the MYSQL structure to operate on
9395 @param[out] result CR_OK : Success, CR_ERROR : error reading,
9396 CR_SERVER_HANDSHAKE_ERR : malformed handshake data
9397
9398 @retval NET_ASYNC_NOT_READY authentication not yet complete
9399 @retval NET_ASYNC_COMPLETE authentication done
9400 */
9401 6 static net_async_status native_password_auth_client_nonblocking(
9402 MYSQL_PLUGIN_VIO *vio, MYSQL *mysql, int *result) {
9403
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_TRACE;
9404 int io_result;
9405 uchar *pkt;
9406
2/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6 mysql_async_auth *ctx = ASYNC_DATA(mysql)->connect_context->auth_context;
9407
9408 6 switch (static_cast<client_auth_native_password_plugin_status>(
9409
1/3
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
6 ctx->client_auth_plugin_state)) {
9410 6 case client_auth_native_password_plugin_status::NATIVE_READING_PASSWORD:
9411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (((MCPVIO_EXT *)vio)->mysql_change_user) {
9412 /* mysql_change_user_nonblocking not implemented yet. */
9413 assert(false);
9414 } else {
9415 /* read the scramble */
9416 net_async_status status =
9417
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 vio->read_packet_nonblocking(vio, &pkt, &io_result);
9418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (status == NET_ASYNC_NOT_READY) {
9419 return NET_ASYNC_NOT_READY;
9420 }
9421
9422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (io_result < 0) {
9423 *result = CR_ERROR;
9424 return NET_ASYNC_COMPLETE;
9425 }
9426
9427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (io_result != SCRAMBLE_LENGTH + 1) {
9428 *result = CR_SERVER_HANDSHAKE_ERR;
9429 return NET_ASYNC_COMPLETE;
9430 }
9431
9432 /* save it in MYSQL */
9433 6 memcpy(mysql->scramble, pkt, SCRAMBLE_LENGTH);
9434 6 mysql->scramble[SCRAMBLE_LENGTH] = 0;
9435 }
9436 6 ctx->client_auth_plugin_state = (int)
9437 client_auth_native_password_plugin_status::NATIVE_WRITING_RESPONSE;
9438
9439 [[fallthrough]];
9440
9441 6 case client_auth_native_password_plugin_status::NATIVE_WRITING_RESPONSE:
9442
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (mysql->passwd[0]) {
9443 char scrambled[SCRAMBLE_LENGTH + 1];
9444
3/8
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 DBUG_PRINT("info", ("sending scramble"));
9445
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 scramble(scrambled, (char *)pkt, mysql->passwd);
9446
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 net_async_status status = vio->write_packet_nonblocking(
9447 vio, (uchar *)scrambled, SCRAMBLE_LENGTH, &io_result);
9448
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (status == NET_ASYNC_NOT_READY) {
9449 return NET_ASYNC_NOT_READY;
9450 }
9451
9452
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (io_result < 0) {
9453 *result = CR_ERROR;
9454 return NET_ASYNC_COMPLETE;
9455 }
9456 } else {
9457
3/8
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 DBUG_PRINT("info", ("no password"));
9458
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 net_async_status status = vio->write_packet_nonblocking(
9459 vio, nullptr, 0, &io_result); /* no password */
9460
9461
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (status == NET_ASYNC_NOT_READY) {
9462 return NET_ASYNC_NOT_READY;
9463 }
9464
9465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (io_result < 0) {
9466 *result = CR_ERROR;
9467 return NET_ASYNC_COMPLETE;
9468 }
9469 }
9470 6 break;
9471 default:
9472 assert(0);
9473 }
9474
9475 6 *result = CR_OK;
9476 6 return NET_ASYNC_COMPLETE;
9477 6 }
9478 /* clang-format off */
9479 /**
9480 @page page_protocol_connection_phase_authentication_methods_clear_text_password Clear text client plugin
9481
9482 <ul>
9483 <li>
9484 This client side plugin is used by a number of server plugins:
9485 LDAP (*authentication_ldap_simple*) and PAM (*authentication_pam*) to name a few.
9486 </li>
9487 <li>
9488 The client name is *mysql_clear_password*
9489 </li>
9490 <li>
9491 Client side requires nothing from the server. But the server generates
9492 and sends a 20-byte
9493 @ref page_protocol_connection_phase_authentication_methods_native_password_authentication
9494 compatible scramble.
9495 </li>
9496 <li>
9497 Client side sends the password in clear text to the server
9498 </li>
9499 </ul>
9500
9501 @startuml
9502 Server->Client: 20 bytes of scramble to be ignored
9503 Client->Server: The clear text password. null terminated.
9504 @enduml
9505
9506 @note
9507 Sending the scramble is not necessary for the clear text
9508 method, but, since the server always initiates the exchange by
9509 sending @ref page_protocol_connection_phase_packets_protocol_handshake
9510 and that one has a placeholder for authentication plugin dependent data the
9511 server does fill that space with a scramble should it come to pass that
9512 it will back down to
9513 @ref page_protocol_connection_phase_authentication_methods_native_password_authentication.
9514 This is also why it's OK no to specifically read this in
9515 @ref clear_password_auth_client since it's already read as a part of
9516 the initial exchange.
9517
9518
9519 @sa ::clear_password_auth_client, ::server_mpvio_write_packet,
9520 ::send_server_handshake_packet
9521 */
9522 /* clang-format on */
9523
9524 /**
9525 The main function of the mysql_clear_password authentication plugin.
9526 */
9527
9528 12 static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) {
9529 int res;
9530
9531 /* send password in clear text */
9532 24 res = vio->write_packet(vio, (const unsigned char *)mysql->passwd,
9533 12 (int)strlen(mysql->passwd) + 1);
9534
9535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 return res ? CR_ERROR : CR_OK;
9536 }
9537
9538 308318 const char *fieldtype2str(enum enum_field_types type) {
9539
16/31
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 384 times.
✓ Branch 4 taken 1362 times.
✓ Branch 5 taken 7213 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 267794 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 131 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 275 times.
✓ Branch 13 taken 7 times.
✓ Branch 14 taken 21875 times.
✓ Branch 15 taken 3646 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 6 times.
✓ Branch 22 taken 506 times.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 4922 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 168 times.
✓ Branch 29 taken 1 times.
✓ Branch 30 taken 27 times.
308318 switch (type) {
9540 1 case MYSQL_TYPE_BIT:
9541 1 return "BIT";
9542 case MYSQL_TYPE_BLOB:
9543 return "BLOB";
9544 case MYSQL_TYPE_BOOL:
9545 return "BOOLEAN";
9546 384 case MYSQL_TYPE_DATE:
9547 384 return "DATE";
9548 1362 case MYSQL_TYPE_DATETIME:
9549 1362 return "DATETIME";
9550 7213 case MYSQL_TYPE_NEWDECIMAL:
9551 7213 return "NEWDECIMAL";
9552 case MYSQL_TYPE_DECIMAL:
9553 return "DECIMAL";
9554 267794 case MYSQL_TYPE_DOUBLE:
9555 267794 return "DOUBLE";
9556 case MYSQL_TYPE_ENUM:
9557 return "ENUM";
9558 case MYSQL_TYPE_FLOAT:
9559 return "FLOAT";
9560 131 case MYSQL_TYPE_GEOMETRY:
9561 131 return "GEOMETRY";
9562 case MYSQL_TYPE_INT24:
9563 return "INT24";
9564 275 case MYSQL_TYPE_JSON:
9565 275 return "JSON";
9566 7 case MYSQL_TYPE_LONG:
9567 7 return "LONG";
9568 21875 case MYSQL_TYPE_LONGLONG:
9569 21875 return "LONGLONG";
9570 3646 case MYSQL_TYPE_LONG_BLOB:
9571 3646 return "LONG_BLOB";
9572 case MYSQL_TYPE_MEDIUM_BLOB:
9573 return "MEDIUM_BLOB";
9574 case MYSQL_TYPE_NEWDATE:
9575 return "NEWDATE";
9576 case MYSQL_TYPE_NULL:
9577 return "NULL";
9578 case MYSQL_TYPE_SET:
9579 return "SET";
9580 case MYSQL_TYPE_SHORT:
9581 return "SHORT";
9582 6 case MYSQL_TYPE_STRING:
9583 6 return "STRING";
9584 506 case MYSQL_TYPE_TIME:
9585 506 return "TIME";
9586 case MYSQL_TYPE_TIMESTAMP:
9587 return "TIMESTAMP";
9588 case MYSQL_TYPE_TINY:
9589 return "TINY";
9590 case MYSQL_TYPE_TINY_BLOB:
9591 return "TINY_BLOB";
9592 4922 case MYSQL_TYPE_VARCHAR:
9593 4922 return "VARCHAR";
9594 case MYSQL_TYPE_VAR_STRING:
9595 return "VAR_STRING";
9596 168 case MYSQL_TYPE_YEAR:
9597 168 return "YEAR";
9598 1 case MYSQL_TYPE_INVALID:
9599 1 return "?-invalid-?";
9600 27 default:
9601 27 return "?-unknown-?";
9602 }
9603 }
9604